我正在探索Java Stream API的可能性,以便找出是否可以用基于流的构造替换所有基于循环的构造。 作为一个可能暗示这实际上是可能的假设的例子,请考虑这个:
是否可以使用Stream API将包含由空格分隔的单词的字符串拆分为字符串数组,如下面的String.split(String)
调用那样?
String[] tokens = "Peter Paul Mary".split(" ");
我知道基于流的解决方案可以使用String.split(String)
方法,如下所示:
Stream.of("Peter Paul Mary".split(" "))
.collect(Collectors.toList());
或使用Pattern.splitAsStream(CharSequence)
(其实现肯定使用基于循环的方法)但我正在寻找一个仅限流的解决方案,这意味着与Haskell片段类似:
words :: String -> [String]
words s = case dropWhile Char.isSpace s of
"" -> []
s' -> w : words s''
where (w, s'') = break Char.isSpace s'
我问这个是因为我仍然想知道Stream API的引入是否会导致我们在Java中处理对象集合的方式发生深刻变化,或者只是为其添加另一个选项,从而使维护更长的代码库,而不是从长远来看简化此任务。
编辑:虽然有一个公认的答案(见下文),但它只表明在这种特殊情况下它是可能的。我仍然对问题中所要求的一般案例的任何提示感兴趣。
答案 0 :(得分:7)
这里有一个独特的非答案:你问的是错误的问题!
所有“循环相关”的Java代码行都可以转换为 streamish 。
因为:良好的编程能够编写人类可以轻松阅读和理解的代码。
因此,如果有人提出一条规则,即“我们只使用流来完成我们所做的一切”,那么该规则会在编写代码时显着减少您的选项。而不是能够仔细地决定“我应该使用流”还是“我应该选择一个简单的老式循环结构”,而是“我如何使用流来处理这个”!
从这个角度来看,您应该专注于提出适用于开发团队中所有人的“规则”。这可能意味着 empasize 使用流构造。但是你绝对想要避免绝对主义,并让每个开发人员以“最可读”的方式编写实现给定需求的代码。如果可以使用溪流,那很好。如果没有,请不要强迫人们这样做。
除此之外:根据您的具体操作,使用流还会带来性能成本。因此,即使您可以找到问题的流解决方案 - 您也必须了解其运行时成本。您肯定希望避免在其成本太多的地方使用流(特别是当该代码已经在关于性能的“关键路径”上时,例如:每秒调用数十亿次)。
最后:在某种程度上,这是技能的问题。含义:当您训练使用流时,您可以更轻松地读取其他人编写的“流线型”代码和B)提出“流线型”解决方案,这些解决方案实际上很容易读。换句话说:这又取决于您正在使用的上下文。另一周,我正在教另一个团队“清洁代码”,我的最后一个代码是“Clean Code,Java8 streams / lambdas”。一个人问我“什么是溪流?”没有必要强迫这样的社区明天用流做任何。
答案 1 :(得分:3)
只是为了好玩(这是一种可怕的方式),我也不知道这是否符合您的需求:
List<String> result = ",,,abc,def".codePoints()
.boxed()
// .parallel()
.collect(Collector.of(
() -> {
List<StringBuilder> inner = new ArrayList<>();
inner.add(new StringBuilder());
return inner;
},
(List<StringBuilder> list, Integer character) -> {
StringBuilder last = list.get(list.size() - 1);
if (character == ',') {
list.add(new StringBuilder());
} else {
last.appendCodePoint(character);
}
},
(left, right) -> {
left.get(left.size() - 1).append(right.remove(0));
left.addAll(right);
return left;
},
list -> list.stream()
.map(StringBuilder::toString)
.filter(x -> !x.equals(""))
.collect(Collectors.toList())
));