Java函数式编程



在一门关于Java函数式编程的初学者课程中,我看到了以下示例:

List.of("abc","def").stream().forEach(element -> System.out.println(element));

这是最基本的例子。在所有其他示例中,使用stream()函数的模式几乎相同。有人提到stream()是用来生成一个对象源的。

我的问题是我们需要流吗?

不能吗?:

List.of("abc","def").forEach(element -> System.out.println(element));

我需要帮助理解的另一件事是:;在函数编程中,函数的使用方式与数据的使用方式类似">

在上面的例子中,这意味着什么?

它是否指的是element -> System.out.println(element)部分是如何以类似于数据的方式使用的?

我的问题是我们需要流吗?

不适用于此示例。forEach是一片独特的雪花;它是唯一一个直接在列表中的,大多数其他流内容(mapfiltermax,诸如此类的内容)都只在流中。

更一般地说,不应使用forEach。它完全不如普通的for循环。它在三个方面是不透明的:

  • 它不是控制流透明的(不能从lambda内部中断/继续在lambda外部定义的循环;也不能返回包含lambda内部的方法)
  • 它不是检查异常透明的(不能在lambda内部throw检查异常,即使lambda周围的上下文捕获了它们)
  • 它不是可变的透明局部变量:不能读取或写入lambda外部定义的任何局部变量,除非该变量(实际上)是final

这些都是显著的缺点。在某些情况下,所有3个都不相关,但lambda也没有好处,因此,不要将list.forEach与lambda一起使用。

列表上的forEach本身是唯一,当您有一个来自其他地方的Consumer<T>时,例如,在一个字段中,可以使用它。

可以使用流上的forEach方法,但除非应用了一系列流操作,否则它没有任何意义。例如:

list.stream()
.filter(x -> x.length() > 6)
.map(String::toLowerCase()
.forEach(System.out::println)
;

这可能仍然不是一个好主意(只需使用for循环),但它没有那么可怕;必须使用闪亮的新锤子"作为CCD_ 13。

在函数编程中,函数的使用方式与数据的使用方式类似。

有点含糊不清。它通常指的是函数可以像变量一样传递的概念。例如,您可以编写一个函数来记录从字符串中删除了多少元素,并且您希望调用方传递给该函数";如何判断是否应该删除元素&";。你可以做什么:

public static <T> int removeIfCount(List<T> elems, Predicate<T> filter) {
int a = elems.size();
elems.removeIf(filter);
int b = elems.size();
return b - a;
}

这里的调用代码可以例如调用:

List<String> names = ...;
int count = removeIfCount(names, x -> x.length() > 6);

它会删除所有长度超过6个字符的名称,并统计删除的名称数量。在这里,我们像传递数据一样传递函数——我们的removeIfCount代码只接受函数作为Predicate<T>变量并传递它。就像传递数据的方式一样。

我将尝试解释CollectionsStreams之间的区别,这在这里解释了

集合和流虽然有一些表面上的相似之处,但目标不同。藏品主要涉及对其元素的有效管理和访问。相比之下,流不提供直接访问或操作其元素的手段,而是关心声明性地描述其源以及将在该源上聚合执行的计算操作。

如果我们在这里检查,它可以帮助理解什么是Stream,以及为什么它说

有人提到stream()用于生成对象源。

最新更新