当它说接口的方法 returns 时,API 是什么意思?

What it mean by the API when it says the interface's method returns something?

我知道我们不能实例化一个接口,但是在学习一本关于 Streams 的教程时,我感到很困惑。

我只会用代码部分来突出我不明白的部分。

// count occurences of each word in a Stream<String> sorted by word
    Map<String, Long> wordCounts =
        Files.lines(Paths.get("Chapter2Paragraph.txt"))
             .map(line -> line.replaceAll("(?!')\p{P}", ""))
             .flatMap(line -> pattern.splitAsStream(line))
             .collect(Collectors.groupingBy(String::toLowerCase,
                TreeMap::new, Collectors.counting()));

对于方法 flatMap,当在 API 中点击时,它说:

Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.)

那么这是什么意思呢?我有点了解它的作用,但我根本不了解它在幕后是如何工作的。在这种情况下,当 API 提到 return 时,它 return 是一个对象还是意味着它会替换当前流?此外,当使用 Streams 时,编译器是否真的创建了这些元素的对象,然后在完成后终止?

此外,从上面的代码来看,我只是想确保我是正确的。 当你有一个 Map<String, Long> wordCounts 变量时,是否意味着在流终止结束时,最终结果必须完全遵循类型推断?

flapMap() 将每个元素变成一个流(任何类型)。这些流连接在一起形成一个大流。

在您的示例中,在按照模式(未在问题中指定)分割每一行之后,整个文件被流式传输(作为一个流)。

您似乎已经基本正确地分析了情况,但您可能对某些中间步骤感到模糊。

您有一个方法链,调用链中前一个方法的 return 值。最终方法 (collect) 的 return 值存储在名为 wordCountsMap 中。忽略这些方法的确切作用和它们的作用 return(暂时),当您调用这样的方法链时,这是标准行为。

地图的通用类型由最终方法调用中的String::toLowerCaseCollectors.counting()决定。前者指定键类型为String,后者指定值为Long。例如,如果您使用 String::length 作为键,您将得到一个 Map<Integer, Long> 类型的映射,它会计算给定长度的单词出现的次数。

回到函数调用的顺序,可以细分如下:

    文件中的
  1. Files.lines(Path) creates a Stream<String> 行。由于结果是一个流,您现在可以调用...
  2. Stream.map(Function<String, String>) 使用对 line.replaceAll(...).
  3. 的调用将输入的字符串流转换为另一个字符串流
  4. 编辑行流现在得到 Stream.flatMap(Function<String, Stream<String>>) 以将行拆分为单词和 return 单个连续流。请记住,pattern.splitAsStream 将按顺序应用于每一行,因此 return 有多少行就有多少流。 Stream.flatMap 获取所有这些流并将它们串成一个连续的流。

    请注意,封装的全部目的是您不必确切知道该过程在幕后是如何工作的。您只需要知道最终结果是什么(在本例中为 Stream<String>)。您应该能够交换一个实现,该实现将所有流预先读取到底层集合中,并且 returns 一个流与一个在处理元素时懒惰地打开每个流的流,而不必担心真正发生的事情.

  5. 现在文件中有 Stream<String> 个单词,您可以应用所谓的终端操作:Stream.collect(Collector<String, String, Map<String, Long>>)。收集器由 Collectors.groupingBy(Function<String, String>, Supplier<Map<String, String>>, Collector<String, String, Long>). This creates a collector that groups the input stream into sub-streams according to the key returned by the classifier Function (String.toLowerCase()) and passes it into a "downstream" collector to do the actual accumulation on each sub-stream. The resulting accumulation is stored into the map returned by the Supplier (TreeMap::new). The downstream Collector is created by Collectors.counting() 创建,它只计算每个流中的元素数。

我已经扩展了此描述中的所有泛型类型,以便更容易理解并查看每个步骤产生的对象种类。

更笼统地说,Java 中的流有两种类型的操作:中间操作和终端操作。流来自一个源(在本例中是您的文件)。所有中间操作 (1-3) 将一个流变成另一个流。输入和输出类型始终明确定义,正如我在上面所示,就像任何其他操作一样。终端操作是 return 基于流的某种单一值。在你的例子中,你计算单词频率并将它们存储到 Map 中。这在 java.util.stream package summary.

中有很好的记录