这个问题更笼统,与两种风格的利弊无关。问题是,我是否应该尽可能使用Stream而不是for循环,因为它具有良好的声明性且具有良好的可读性?
我正在和我的同事争论使用流和for循环的优缺点。我同意我们应该在90%的时间内首选流,但是我相信在某些情况下,最好使用for循环而不是流。
例如,我需要对元素集合执行一些操作,而这些操作可能会引发Checked Exception。在操作过程中,如果任何元素发生异常,我都想完全退出执行,因此我将其用于循环并将其包装在try / catch块中。我的同事不满意,因为结果占用的行数比如果我要使用流的情况多两倍。我通过创建自己的自定义功能接口(重写了受检查的异常和静态方法,将它们转换为引发未检查的异常(此处为示例))重写了它,最后看起来像这样:
try {
Map<String, String> someResult= elements.stream()
.filter(throwingPredicateWrapper(element-> client.hasValue(element)))
.collect(
Collectors.toMap(Function.identity(),
throwingFunctionWrapper(element -> client.getValue(element))));
return someResult;
} catch (Exception e) {
LOGGER.error("Error while processing", e);
}
Run Code Online (Sandbox Code Playgroud)
他很高兴,因为它花了不到两倍的时间来编写代码。
这是一个简单的示例,看起来还不错,但是我相信这里的旧循环是处理这种情况的更简单,更快捷的方法。我们是否应该倾向于尽可能地使用Streams?
Joshua Bloch,《Effective Java》的作者,有一篇很好的演讲,涉及何时使用流。30:30 左右开始观看他的“明智地使用流”部分。
尽管这很大程度上是基于意见的,但他认为您不想立即开始将所有程序循环转变为流,但您确实需要一种平衡的方法。他至少提供了一种示例方法,这样做会创建更难以理解的代码。他还认为,在许多情况下,是否以程序性方式或以更实用的方式编写它并没有正确的答案,并且它取决于上下文(我认为团队决定共同做的事情可能会发挥作用)。他在GitHub上有示例,下面的所有示例都来自他的 GitHub 存储库。
这是他提供的迭代字谜方法的示例,
// Prints all large anagram groups in a dictionary iteratively (Page 204)
public class IterativeAnagrams {
public static void main(String[] args) throws IOException {
File dictionary = new File(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
Map<String, Set<String>> groups = new HashMap<>();
try (Scanner s = new Scanner(dictionary)) {
while (s.hasNext()) {
String word = s.next();
groups.computeIfAbsent(alphabetize(word),
(unused) -> new TreeSet<>()).add(word);
}
}
for (Set<String> group : groups.values())
if (group.size() >= minGroupSize)
System.out.println(group.size() + ": " + group);
}
private static String alphabetize(String s) {
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
}
Run Code Online (Sandbox Code Playgroud)
这里使用的是 Streams ,
// Overuse of streams - don't do this! (page 205)
public class StreamAnagrams {
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
try (Stream<String> words = Files.lines(dictionary)) {
words.collect(
groupingBy(word -> word.chars().sorted()
.collect(StringBuilder::new,
(sb, c) -> sb.append((char) c),
StringBuilder::append).toString()))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.map(group -> group.size() + ": " + group)
.forEach(System.out::println);
}
}
}
Run Code Online (Sandbox Code Playgroud)
他主张采用平衡的第三种方法,同时使用这两种方法,
// Tasteful use of streams enhances clarity and conciseness (Page 205)
public class HybridAnagrams {
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
try (Stream<String> words = Files.lines(dictionary)) {
words.collect(groupingBy(word -> alphabetize(word)))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.forEach(g -> System.out.println(g.size() + ": " + g));
}
}
private static String alphabetize(String s) {
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
}
Run Code Online (Sandbox Code Playgroud)