The 30 second answer
I count characters with groupingBy into a LinkedHashMap so first-occurrence order is kept, then walk the entries and take the first with count one. A plain HashMap would lose order. I also mention chars gives UTF-16 code units, so for emoji I would use codePoints instead.
Optional<Character> c = s.chars()
.mapToObj(ch -> (char) ch)
.collect(Collectors.groupingBy(
Function.identity(),
LinkedHashMap::new,
Collectors.counting()))
.entrySet().stream()
.filter(e -> e.getValue() == 1)
.map(Map.Entry::getKey)
.findFirst();LinkedHashMap::new preserves first-occurrence order; the default groupingBy map has no order guarantee.
Caveat: chars() yields UTF-16 code units; use codePoints() for emoji and supplementary characters.
Sources:
Sources (0)
See inline citations in the answer above.