筛选和切片

用谓词筛选-filter

1
2
3
menu.stream()
	.filter(Dish::isVegetarian)
	.collect(Collectors.toList());

取重-distinct

1
2
3
4
5
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
	.filter(integer -> integer % 2 == 0)
	.distinct()
	.forEach(System.out:: println);

截短流-limit

1
2
3
menu.stream().filter(dish -> dish.getCalories() > 300)
     .limit(3)
     .forEach(System.out:: println);

跳过元素-skip

1
2
3
menu.stream().filter(dish -> dish.getCalories() > 300)
                .skip(2)
                .forEach(System.out:: println);

映射

map

获取菜单中菜名的length。

1
2
3
4
menu.stream()
	.map(Dish::getName)
	.map(String::length)
	.forEach(System.out:: println);

flatMap

拆分单词字母并取重。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
List<String> words = Arrays.asList("Hello", "World");
// ❌错误,返回2个字符串数组
words.stream().map(word -> word.split("")).distinct()
                .forEach(System.out::println);
// ❌错误,返回2个java.util.stream.ReferencePipeline$Head类型数组                
words.stream().map(word -> word.split("")).map(Arrays::stream)
                .distinct().forEach(System.out::println);
// ✅ 正确做法
words.stream().map(word -> word.split("")).flatMap(Arrays::stream)
                .distinct().forEach(System.out::println);

查找匹配

匹配

至少匹配一个-anyMatch
1
2
3
if (menu.stream().anyMatch(Dish::isVegetarian)){
	System.out.println("This menu is (somewhat) vegetarian friendly");
}
全部匹配-allMatch
1
2
3
if (menu.stream().allMatch(dish -> dish.getCalories() < 1000)) {
	System.out.println("This menu is healthy");
}
全不匹配-noneMatch
1
2
3
if (menu.stream().noneMatch(dish -> dish.getCalories() >= 1000)) {
	System.out.println("This menu is healthy");
}

anyMatch,allMatch,noneMatch都用到了短路求值。

查找

查找返回当前流中任意元素-findAny
1
2
3
menu.stream().filter(Dish::isVegetarian)
                .findAny()
                .ifPresent(d -> System.out.println(d.getName()));

Optional类( java.util.Optional)是一个容器类,代表一个值存在或不存在。findAny返回Optional类型。Optional几个常用方法:

  • isPresent() 将在Optional包含值的时候返回true, 否则返回false。
  • ifPresent( Consumer< T> block)会在值存在的时候执行给定的代码块。
  • T get() 会在值存在时返回值,否则抛出一个NoSuchElement异常。
  • T orElse( T other)会在值存在时返回值,否则返回一个默认值。
查找第一个元素-findFirst
1
2
3
// n的平方后能被3整除的第一个元素
numbers.stream().map(n -> n * n).filter(n -> n % 3 ==0).findFirst()
                .ifPresent(System.out:: println);

归约-reduce

元素求和

1
2
3
4
//Lambda
numbers.stream().reduce(0, (a, b) -> a + b);
//方法引用
numbers.stream().reduce(Integer::sum).get()

最大值、最小值

1
2
numbers.stream().reduce(Integer::max).get()
numbers.stream().reduce(Integer::min).get()

流的状态,无状态和有状态

无状态

mapfilter等操作会从输入流中获取每一个元素,并在输出流中得到 0 或 1 个结果。 这些操作一般都是没有内部状态的。

有状态

reducesummax等操作需要内部状态来累积结果。

流常用操作

操作 类型 返回类型 使用的类型/函数接口 函数描述符号
filter 中间 Stream Predicate T -> boolean
distinct 中间(有状态-无界) Stream
skip 中间(有状态-有界) Stream long
limit 中间(有状态-有界) Stream long
map 中间 Stream Function T -> R
flatMap 中间 Stream Function> T -> Stream
sorted 中间(有状态-无界) Stream Comparator (T, T) -> int
anyMatch 终端 boolean Predicate T -> boolean
noneMatch 终端 boolean Predicate T -> boolean
allMatch 终端 boolean Predicate T -> boolean
findAny 终端 Optional
findFirst 终端 Optional
forEach 终端 void Consumer T -> void
collect 终端 R Collector
reduce 中间(有状态-有界) Optional BinaryOperator (T, T) -> T
count 终端 long

数值流

原始类型特化流IntStream,LongStream,DoubleStream

  • 映射对象到值流mapToInt,mapToLong,mapToDouble

    1
    2
    3
    4
    
    menu.stream().mapToInt(Dish::getCalories).sum();
    menu.stream().mapToInt(Dish::getCalories).max();
    menu.stream().mapToInt(Dish::getCalories).min();
    menu.stream().mapToInt(Dish::getCalories).average();
  • 转换回对象流boxed()

    1
    2
    
    IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
    Stream<Integer> stream = intStream.boxed();
  • Optional类型OptionalInt,OptionalLong,OptionalDouble

    1
    2
    
    OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();
    int max = maxCalories.orElse(1);

数值范围

IntStreamLongStream分别提供了静态方法rangerangeClosed

1
2
// 1到100之内的偶数
IntStream evenNumbers = IntStream.rangeClosed(1, 100).filter(i -> i % 2 == 0);

示例,计算1~100到勾股数,如(3, 4, 5)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
IntStream.rangeClosed(1, 100).boxed()
    .flatMap(a -> IntStream.rangeClosed(a, 100)
        .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
        .mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a * a + b * b)}))
    .limit(5)
    .forEach(arr -> System.out.println(
        "(" + arr[0] + ","
        + arr[1] + ","
        + arr[2] + ")"
    )
);
   
// better 
IntStream.rangeClosed(1, 100).boxed()
    .flatMap(a -> IntStream.rangeClosed(a, 100)
        .mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)})
        .filter(arr -> arr[2] % 1 == 0))
    .limit(5)
    .forEach(arr -> System.out.println(
        "(" + arr[0] + ","
        + arr[1] + ","
        + arr[2] + ")"
    )
);

构建流

由值创建流

1
2
3
4
//Stream.of
Stream<String> stringStream = Stream.of("Java 8", "Lambda", "In", "Action");
//创建空流
Stream<String> emptyStream = Stream.empty();

由数组创建流

1
2
3
//Arrays.stream
int[] intArrs = {1, 2, 3, 4};
System.out.println(Arrays.stream(intArrs).sum());

由文件生成流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
long wordCount = 0;
try(Stream<String> lines = Files.lines(Paths.get("data.txt"), 
    Charset.defaultCharset())) {
    wordCount = lines.flatMap(line -> Arrays.stream(line.split(" ")))
            //.map(w -> new String[]{w, })
            .distinct().count();
    System.out.println(wordCount);

} catch (IOException e) {
    e.printStackTrace();
}

由函数生成流-无限流Stream.iterate,Stream.generate

迭代Stream.iterate
1
2
3
4
5
6
7
// 输出:0, 2, 4
Stream.iterate(0, n -> n + 2).limit(3).forEach(System.out:: println);
// 斐波纳契序列
Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]})
      .limit(10)
      .map(t -> t[0])
      .forEach(System.out:: println);
生成Stream.generate
1
2
// 0~1直接的随机数
Stream.generate(Math::random).limit(5).forEach(System.out:: println);

自定义Supplier实现斐波纳契序列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
IntSupplier fib = new IntSupplier() {
            private int previous = 0;
            private int current = 1;

            @Override
            public int getAsInt() {
                int oldPrevious = previous;
                int nextValue = previous + current;
                previous = current;
                current = nextValue;
                return oldPrevious;
            }
        };
IntStream.generate(fib).limit(5).forEach(System.out:: println);

本文为学习记录,因能力有限,如有错误请赐教……如需转载,请注明出处!