通过一些有用的输入,我用更少的代码调整了我的答案:
public class FirstRepeat {
public static void main(String[] args) {
Map<Character, Long> collect = "abcsdnvs".chars().mapToObj(i -> (char)i).collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
collect.forEach( (x,y) -> System.out.println( "Key: " + x + " Val: " + y));
Optional<Character> firstNonRepeat = collect.entrySet().stream().filter( (e) -> e.getValue() == 1).map(e -> e.getKey()).findFirst();
if(firstNonRepeat.isPresent()) {
System.out.println("First non repeating:" + firstNonRepeat.get());
}
Optional<Character> firstRepeat = collect.entrySet().stream().filter( (e) -> e.getValue() > 1).map(e -> e.getKey()).findFirst();
System.out.println("First repeating:" + firstRepeat.orElse(null));
}
}
上面的作用是:
- 创建字符流:
"abcsdnvs".chars().mapToObj(i -> (char)i)
- 使用收集器对这些字符进行分组:
.collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
该分组分为 3 个不同的部分:
- 分类器
正如所指出的,我可以使用 Function.identity() 来实现这一点。相当于x -> x
。这意味着我们是按实际角色分组的。
- 地图工厂
我们正在使用LinkedHashMap::new
为了这。原因是我们需要保留插入顺序才能找到第一个元素。默认实现使用 HashMap,它不会保留插入顺序。
- 下游收集器
由于我们正在使用分组,因此我们需要决定如何收集分组的元素。在这种情况下,我们需要出现的次数。为此,您可以使用:Collectors.counting()
这将简单地总结给定角色有多少个可用元素。
然后程序打印:
Key: a Val: 1
Key: b Val: 1
Key: c Val: 1
Key: s Val: 2
Key: d Val: 1
Key: n Val: 1
Key: v Val: 1
First non repeating:a
First repeating:s
我们使用流操作来查找第一个元素(基于过滤器):
Optional<Character> firstNonRepeat = collect.entrySet().stream().filter( (e) -> e.getValue() == 1).map(e -> e.getKey()).findFirst();
我们可以在其中流式传输分组元素,并按 ( 的值过滤它们>1
第一次重复,==1
对于第一个非重复字符)。这findFirst
如果存在这样的元素,则方法返回该元素。
返回值是一个可选值,应该安全地处理。正如所指出的,您可以使用isPresent()
检查是否已找到值(请参阅第一个打印语句)或使用orElse(...)
返回默认值而不是抛出异常(请参阅打印语句编号 2,其中我返回 null 作为默认值,以防止在没有找到重复字母的情况下抛出异常)