就像魔术棒一样,中间操作将一个Stream转换为另一个Stream。 这些操作可以无穷无尽的方式组合在一起,以可读有效的方式执行从简单到高度复杂的任务。

本文是五分之二,其中还有一个GitHub存储库,其中包含每个单元的说明和练习。

  • 第1部分:创建流
  • 第2部分:中级操作
  • 第三部分:终端操作
  • 第4部分:数据库流
  • 第5部分:使用流创建数据库应用程序

中级业务

中间操作充当应如何转换Stream元素的声明性(功能性)描述,它们共同构成了元素流经的管道。 该行结尾的内容自然取决于管道的设计方式。

与机械流水线相反,Stream流水线中的中间操作可能(*)呈现新的Stream,该流可能取决于先前阶段中的元素。 对于map操作(我们将在稍后介绍),新的Stream甚至可能包含其他类型的元素。



java中级上机考试 java中级教程_字符串



(*)严格来说,不要求执行中间操作来创建新的Stream。 相反,它可以更新其内部状态,或者,如果中间操作未进行任何更改(例如.skip(0) ),则返回上一级的现有Stream。

要大致了解管道的外观,请回想一下上一篇文章中使用的示例:

List<String> list = Stream.of( "Monkey" , "Lion" , "Giraffe" , "Lemur" ) 
     .filter(s -> s.startsWith( "L" )) 
     .map(String::toUpperCase) 
     .sorted() 
     .collect(toList());  System.out.println(list);
[LEMUR, LION]

现在,我们将继续详细解释这些操作和其他操作的含义。

根据我们的经验, filter()是Stream API最有用的操作之一。 它使您可以将Stream缩小为适合特定条件的元素。 此类标准必须表示为Predicate (导致boolean值的函数),例如lambda。 以下代码的目的是查找以字母“ L”开头的字符串,并丢弃其他字符串。

Stream<String> startsWithT = Stream.of( 
    "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
     .filter(s -> s.startsWith( "L" ));
startsWithT: [Lion, Lemur]

有一些非常简单但功能强大的操作,提供了一种根据元素在Stream中的位置选择或丢弃元素的方法。 这些操作中的第一个是limit(n) ,它基本上按照其说的进行操作–它创建一个新流,该流仅包含应用该流的前n个元素。 下面的示例说明了如何将四只动物的流简化为仅“猴子”和“狮子”。

Stream<String> firstTwo = Stream.of( 
    "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
    .limit( 2 );
firstTwo: [Monkey, Lion]

同样,如果只对线下的某些元素感兴趣,则可以使用.skip(n) -operation。 如果将skip(2)应用于动物流,则会留下尾巴两个元素“长颈鹿”和“狐猴”。

Stream<String> firstTwo = Stream.of( 
    "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
    .skip( 2 );
lastTwo: [Giraffe, Lemur]

在某些情况下,流中每个元素只需要出现一次即可。 无需手动筛选出任何重复项,而是为此目的存在了一个指定的操作-distinct distinct() 。 它将使用Object::equals检查是否相等,并返回仅包含唯一元素的新Stream。 这类似于集合。

Stream<String> uniqueAnimals = Stream.of( 
    "Monkey" , "Lion" , "Giraffe" , "Lemur" , "Lion"  ) 
    .distinct();
uniqueAnimals: [“Monkey”, “Lion”, “Giraffe”, “Lemur”]

有时,元素的顺序很重要,在这种情况下,我们希望控制事物的排序方式。 最简单的方法是使用排序操作,该操作将以自然顺序排列元素。 对于以下字符串,这表示字母顺序。

Stream<String> alphabeticOrder = Stream.of( 
     "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
    .sorted();
alphabeticOrder: [Giraffe, Lemur, Lion, Monkey]

有时只能以自然顺序排序可能会有些局限。 幸运的是,可以应用自定义Comparator来检查元素的某些属性。 例如,我们可以按照字符串的长度顺序对它们进行排序:

Stream<String> lengthOrder = Stream.of( 
     "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
    .sorted(Comparator.comparing(String::length));
lengthOrder: [Lion, Lemur, Monkey, Giraffe]

我们可以应用于Stream的最通用的操作之一是map() 。 通过将Stream的元素映射到另一个值或类型,它可以将其转换为其他元素。 这意味着此操作的结果可以是任何类型R的Stream。 下面的示例执行从StringString的简单映射,将所有大写字母替换为它们的小写字母。

Stream<String> lowerCase = Stream.of( 
     "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
    .map(String::toLowerCase);
lowerCase: [monkey, lion, giraffe, lemur]

map-operation的三种特殊实现方式仅限于将元素映射到基本类型intdoubledouble
long

.mapToInt();  .mapToDouble();  .mapToLong();

因此,这些操作的结果始终对应于IntStreamDoubleStreamLongStream 。 下面,我们演示如何使用.mapToInt()将动物映射到其名称的长度:

IntStream lengths = Stream.of( 
     "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
    .mapToInt(String::length);
lengths: [ 6 , 4 , 7 , 5 ]

注意:
String::length等于lambda s -> s.length() 。 我们更喜欢前一种表示法,因为它使代码更简洁易读。

尽管本文功能非常强大,但我们将很难理解它的最后一项操作。 它是有关map()操作,但是,而不是采取一个Function ,其从型变为T到返回类型R它需要一个Function ,其从型变为T并返回一个StreamR 。 然后将这些“内部”流平展为生成的流,从而将内部流的所有元素串联在一起。

Stream<Character> chars = Stream.of( 
     "Monkey" , "Lion" , "Giraffe" , "Lemur"  ) 
     .flatMap(s -> s.chars().mapToObj(i -> ( char ) i));
chars: [M, o, n, k, e, y, L, i, o, n, G, i, r, a, f, f, e, L, e, m, u, r]

如果您尚未克隆关联的GitHub存储库,我们建议您现在进行克隆。 本文的内容足以解决名为MyUnit2Intermediate的第二个单元。 相应的Unit2Intermediate接口包含JavaDocs,它们描述MyUnit2MyIntermediate方法的预期实现。

public interface Unit2Intermediate { 
    /** 
     * Return a Stream that contains words that are 
     * longer than three characters. Shorter words 
     * (ie words of length 0, 1, 2 and 3) 
     * shall be filtered away from the stream. 
     * <p> 
     * A Stream of 
     *     ["The", "quick", "quick", "brown", "fox", 
     *     "jumps", "over", "the", "lazy", "dog"] 
     * would produce a Stream of the elements 
     *     ["quick", "quick", "brown", "jumps", 
     *     "over", "lazy"] 
     */ 
    Stream<String> wordsLongerThanThreeChars(Stream<String> stream);

提供的测试(例如Unit2MyIntermediateTest )将充当自动分级工具,让您知道您的解决方案是否正确。



java中级上机考试 java中级教程_字符串_02



下一篇

在下一篇文章中,我们将继续进行终端操作,并探索如何收集,计数或分组管道的结果元素。 在此之前–祝您编程愉快!

s

Per Minborg和Julia Gustafsson

翻译自: https://www.javacodegeeks.com/2019/10/become-a-master-of-java-streams-part-2-intermediate-operations.html