Java集合和流

时间:2020-01-09 10:35:49  来源:igfitidea点击:

Java Stream API提供了一种更具功能性的编程方法来迭代和处理例如一个集合。 Java Stream API已添加到Java 8中的Java中。本教程仅用于说明如何在Java Collection API上下文中使用Java Stream API。

流被设计为与Java lambda表达式一起使用。本文中的许多示例都将使用lambda表达式,因此,如果我们尚不了解它们,则应在阅读本文之前先阅读它们。

从集合中获取流

我们可以通过调用给定集合的stream()方法来从集合中获取流。这是从集合中获取流的示例:

List<String> items = new ArrayList<String>();

items.add("one");
items.add("two");
items.add("three");

Stream<String> stream = items.stream();

首先创建一个字符串列表,然后向其中添加三个字符串。然后通过调用items.stream()方法获得字符串的" Stream"。这类似于通过调用items.iterator()方法获得"迭代器"的方式,但是"流"与"迭代器"是不同的动物。

流处理阶段

从"集合"实例中获得"流"实例后,就可以使用该流来处理集合中的元素。

处理流中的元素分为两个步骤/阶段:

  • 配置
  • 加工

首先配置流。该配置可以包含过滤器和映射。这些也称为非终端操作。

第二,处理流。该处理包括对过滤后的对象和映射的对象进行处理。在配置呼叫期间不进行任何处理。直到对流调用处理方法。流处理方法也称为终端操作。

Stream.filter()

我们可以使用filter()方法过滤流。这是一个流过滤示例:

stream.filter( item -> item.startsWith("o") );

filter()方法采用Predicate作为参数。 Predicate接口包含一个名为test()的函数,该函数与作为上面参数传递的lambda表达式匹配。换句话说,lambda表达式实现了Predicate.test()方法。

test()方法的定义如下:

boolean test(T t)

它只接受一个参数并返回一个布尔值。如果我们看一下上面的lambda表达式,我们会发现它只接受一个参数item并返回一个布尔值,该布尔值是item.startsWith(" o")方法调用的结果。

当我们在Stream上调用filter()方法时,作为参数传递给filter()方法的过滤器将存储在内部。尚未进行过滤。

传递给filter()函数的参数确定应处理流中的哪些项,以及哪些项应从处理中排除。如果传递给filter()的参数的Predicate.test()方法对某个项目返回true,则意味着应该对其进行处理。如果返回" false",则不处理该项目。

Stream.map()

可以将集合中的项目映射到其他对象。换句话说,对于集合中的每个项目,我们都将基于该项目创建一个新对象。如何完成映射取决于我们。这是一个简单的Java流映射示例:

items.stream()
     .map( item -> item.toUpperCase() )

此示例将" items"集合中的所有字符串映射到它们的大写等效项。

同样,此示例实际上并未执行映射。它仅配置要映射的流。一旦调用了一种流处理方法,就将执行映射(和过滤)。

Stream.collect()

collect()方法是Stream接口上的流处理方法之一。调用此方法时,将进行过滤和映射,并收集由这些操作产生的对象。这是一个stream.collect()示例:

List<String> filtered = items.stream()
    .filter( item -> item.startsWith("o") )
    .collect(Collectors.toList());

这个例子创建了一个流,添加了一个过滤器,并在" List"中收集了过滤器接受的所有对象。过滤器仅接受以字符" o"开头的项目(字符串)。因此,生成的"列表"包含"项目"集合中所有以字符" o"开头的字符串。

Stream.min()和Stream.max()

min()和max()方法是流处理方法。调用这些方法后,将对流进行迭代,应用过滤和映射,并将返回流中的最小值或者最大值。

这是Java的Stream.min()示例:

String shortest = items.stream()
        .min(Comparator.comparing(item -> item.length()))
        .get();

min()和max()方法会返回一个Optional实例,该实例具有一个get()方法,我们可以使用该方法获取该值。如果流中没有元素,则get()方法将返回null。

min()和max()方法采用Comparator作为参数。 Comparator.comparing()方法根据传递给它的lambda表达式创建一个Comparator。实际上," comparing()"方法采用" Function",这是适用于lambda表达式的功能接口。它采用一个参数并返回一个值。

Stream.count()

在应用过滤之后,count()方法仅返回流中元素的数量。这是一个例子:

long count = items.stream()
     .filter( item -> item.startsWith("t"))
     .count();

本示例对流进行迭代,并保留所有以字符" t"开头的元素,然后对这些元素进行计数。

count()方法返回long,这是过滤等后流中元素的数量。

Stream.reduce()

reduce()方法可以将流的元素减少为单个值。这是一个例子:

String reduced2 = items.stream()
        .reduce((acc, item) -> acc + " " + item)
        .get();

" reduce()"方法采用" BinaryOperator"作为参数,可以使用lambda表达式轻松实现。 BinaryOperator.apply()方法是上述lambda表达式实现的方法。此方法有两个参数。 " acc"是累加值," item"是流中的元素。因此,由" reduce()"函数创建的值是在处理流中的最后一个元素之后的累加值。在上面的示例中,每个项目都链接到累加值。这是通过实现" BinaryOperator"的lambda表达式完成的。

BinaryOperator作为参数的reduce()方法返回一个Optional。如果流中不包含任何元素,则Optional.get()返回null。否则,它将返回减小的值。

还有另一个reduce()方法,它带有两个参数。它使用一个初始值作为累加值,然后是一个" BinaryOperator"。这是一个例子:

String reduced = items.stream()
        .reduce("", (acc, item) -> acc + " " + item);

本示例将一个空字符串用作初始值,然后使用与前面的示例相同的lambda表达式。这个版本的reduce()方法直接返回累加值,而不是"可选"值。如果流中不包含任何元素,则将返回初始值。

reduce()方法也可以与filter()方法结合使用。这是一个例子:

String reduced = items.stream()
    .filter( item -> item.startsWith("o"))
    .reduce("", (acc, item) -> acc + " " + item);

此示例保留所有以字符" o"开头的元素,然后将这些元素简化为单个值。