流或循环

Jav*_*Dev 5 java

这个问题更笼统,与两种风格的利弊无关。问题是,我是否应该尽可能使用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?

Bil*_*ill 3

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)