Java 8 流和映射值得吗?

感觉java 8流和映射函数非常冗长,它们并不是真正的改进。例如,我编写了一些代码,使用一个集合来生成另一个修改后的集合:

private List<DartField> getDartFields(Class<?> model) {
    List<DartField> fields = new ArrayList<>();
    for (Field field : model.getDeclaredFields()) {
        if (!Modifier.isStatic(field.getModifiers())) {
            fields.add(DartField.getDartField(field));
        }
    }
    return fields;
}

这似乎是java 8流及其函数的理想用例,所以我这样重写了它:

private List<DartField> getDartFields(Class<?> model) {
    return Arrays.asList(model.getDeclaredFields())
            .stream()
            .filter(field -> !Modifier.isStatic(field.getModifiers()))
            .map(field -> DartField.getDartField(field))
            .collect(Collectors.toList());
}

但我不确定我是否更喜欢这样。它是236个字符,而普通风格的java中有239个字符。它似乎不具有或多或少的可读性。很高兴您不必声明 一个 ,但需要调用和(取决于数据类型)也好不到哪里去。ArrayList.collect(Collectors.toList())Arrays.asList

像这样的使用是否有一些我没有得到的实际改进,或者这只是一种有趣的方式,可以将任何不了解函数式编程的同事扔进一个循环中?.stream()

我想如果我动态传递过滤器或映射lambdas,那将是有用的,但如果你不需要这样做......


答案 1

问题是您没有始终如一地使用API。您将用例限制为可以最好地描述为“实际上不使用API”,因为您坚持返回.这尤其荒谬,因为它是一种方法,因此您也可以完全适应呼叫者。StreamStreamCollectionprivate

考虑将方法更改为

private Stream<DartField> getDartFields(Class<?> model) {
    return Stream.of(model.getDeclaredFields())
            .filter(field -> !Modifier.isStatic(field.getModifiers()))
            .map(field -> DartField.getDartField(field));
}

并查看呼叫者实际上想要做什么。通常,它们本身不需要 a 作为目的,而是希望执行一个操作,甚至更多可以链接的操作,例如打印它们:Collection

getDartFields(Foo.class).forEach(System.out::println);

最有趣的功能是流的懒惰性质,这意味着在返回时,尚未执行任何操作,并且如果您使用这样的操作,则无需处理所有元素。如果返回包含所有元素的 a,您将失去此功能。getDartFieldsfindFirstCollection

这也适用于多步骤处理,其中处理普通列表意味着对于每个步骤,必须创建一个新列表并用结果填充。


答案 2

你可以用不同的方式写它(不一定更好)

private List<DartField> getDartFields(Class<?> model) {
    return Stream.of(model.getDeclaredFields())
            .filter(field -> !Modifier.isStatic(field.getModifiers()))
            .map(DartField::getDartField)
            .collect(Collectors.toList());
}

使用静态导入,这看起来像

private static List<DartField> getDartFields(Class<?> model) {
    return of(model.getDeclaredFields())
            .filter(field -> !isStatic(field.getModifiers()))
            .map(DartField::getDartField)
            .collect(toList());
}

它似乎不具有或多或少的可读性。

恕我直言,情况经常如此。但是,我想说的是,在>10%的情况下,它明显更好。像任何新功能一样,您可能会过度使用它,直到您熟悉它并发现您觉得舒服的量使用它。

使用像这样的.stream()是否有一些我没有得到的实际改进,或者这只是一种有趣的方式,可以将任何不了解函数式编程的同事投入循环?

我怀疑两者都有。如果你不懂函数式编程,它往往是只读代码。也就是说,你仍然可以理解它的作用,问题是你是否必须维护它。

恕我直言,值得鼓励开发人员学习函数式编程,因为它有一些关于如何构建代码的非常有用的想法,即使您不使用FP语法,您也会从中受益。

Streams API 在构造中很有用,您以前不会费心去实现。

例如,假设您要按名称索引字段。

private static Map<String, DartField> getDartFields(Class<?> model) {
    return of(model.getDeclaredFields())
            .filter(field -> !isStatic(field.getModifiers()))
            .map(DartField::getDartField)
            .collect(groupingBy(f -> f.getName()));
}

在过去,您可能使用列表而不是 Map,但是通过简化 Map 的组装,您可能会使用您真正应该更频繁地使用的数据结构。

现在让我们看看如果我们使用更多的线程是否会更快。

private static Map<String, DartField> getDartFields(Class<?> model) {
    return of(model.getDeclaredFields()).parallel()
            .filter(field -> !isStatic(field.getModifiers()))
            .map(DartField::getDartField)
            .collect(groupingByConcurrent(f -> f.getName()));
}

看看这有多难,当你发现它可能弊大于利时,把它改回来也很容易。