Java流方法如何运行?

0 java java-stream

我刚刚了解Java流。可以通过在 Collection 上调用 .stream() 来创建流,然后您可以使用docs中描述的方法对该流进行操作。

我不明白的是这个过程实际发生在哪里。我的意思是我可以创建一个具有年龄属性的 Person 对象流并按如下方式对其进行排序:

Person john = new Person(30);
Person anne = new Person(25);
Person bill = new Person(52);

ArrayList<Person> people = new ArrayList<Person>();
people.add(john);
people.add(anne);
people.add(bill);

ArrayList<Person> sortedPeople = people
.stream()
.sorted(Comparators.comparing(person -> person.getAge()))
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
Run Code Online (Sandbox Code Playgroud)

但在我发现的文档和源代码中,函数式接口(例如包含排序方法的函数式接口)没有排序代码,仅描述传递给它的 lambda 函数。我在这里严重误解了什么吗?

Bas*_*que 7

当您调用 时ArrayList#stream(),您会得到看起来像 a但实际上是实现该接口的某个未指定的具体类Stream的对象。Stream

\n

这是OOP之美的一部分:我们不知道在幕后实际使用了哪些未指定的具体类,我们也不关心。我们所关心的是神秘的具体类(或超类)履行接口(Stream在本例中为接口)承诺的契约。

\n
\n

函数式接口(例如包含排序方法的接口)没有排序代码

\n
\n

该未指定的具体类已实现排序机制,实现接口sorted所需的方法Stream

\n
\n

只是描述了传递的 lambda 函数

\n
\n

您传递的 lambda 是将作为排序机制的一部分执行的实际代码。

\n
\n

如果您仍然对那个神秘的具体类感到好奇,您可以浏览OpenJDKArrayList#stream项目上的开源代码。从这里开始。您\xe2\x80\x99 可能还需要梳理超类的源代码。

\n

并且,您可以询问该Stream对象的具体类。Java中的每个对象都是类的子类Object,因此都有一个方法getClass。使用该类Class,您可以获得该类的名称。

\n
persons.stream().getClass().getCanonicalName()\n
Run Code Online (Sandbox Code Playgroud)\n

当我使用Azul Systems名为Zulu的 Java 17.0.2 实现副本运行此命令时,我得到:

\n
\n

java.util.stream.ReferencePipeline.Head

\n
\n

我在Java 17 API中没有找到任何这样的类。因此,该类必须在我当前使用的任何 Java 实现中内部定义。其他实现可能有所不同,过去和未来的版本也可能有所不同。

\n

如今,大多数 Java 实现都主要基于 OpenJDK 的代码库。这包括祖鲁语。因此,查看 OpenJDK,我确实Head在.ReferencePipeline

\n
\n

顺便说一句,您的代码可以简化为这样的代码。

\n
persons.stream().getClass().getCanonicalName()\n
Run Code Online (Sandbox Code Playgroud)\n
\n

people.toString() = [人[姓名=爱丽丝,年龄=52],人[姓名=鲍勃,年龄=23],人[姓名=卡罗尔,年龄=39]]

\n

sorted.toString() = [人[名字=鲍勃,年龄=23],人[名字=卡罗尔,年龄=39],人[名字=爱丽丝,年龄=52]]

\n
\n