JAVA8使用笔记(一)

java8 — Stream流操作

演示代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// model
package com.wangj.java8demo;
public class Dish {
private final String name;
private final boolean vegetarian;
private final int calories;
private final Type type;
public Dish(String name, boolean vegetarian, int calories, Type type) { this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
@Override
public String toString() {
return name;
}
public enum Type { MEAT, FISH, OTHER }
}
// 演示demo
package com.wangj.java8demo;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
public class TestOne {
public void doIt() {
List<Dish> menu = Arrays.asList(
new Dish("pork", false, 800, Dish.Type.MEAT),
new Dish("beef", false, 700, Dish.Type.MEAT),
new Dish("chicken", false, 400, Dish.Type.MEAT),
new Dish("french fries", true, 530, Dish.Type.OTHER),
new Dish("rice", true, 350, Dish.Type.OTHER),
new Dish("season fruit", true, 120, Dish.Type.OTHER),
new Dish("pizza", true, 550, Dish.Type.OTHER),
new Dish("prawns", false, 300, Dish.Type.FISH),
new Dish("salmon", false, 450, Dish.Type.FISH));
List<String> collect = menu.stream()//从menu获得stream流
.filter(Dish::isVegetarian) //筛选出isVegetarian == true的对象
.map(Dish::getName)//转换并获取name
.limit(3)//只获取前三个
.collect(toList());//将结果存在另一个List中
System.out.println(collect);
//流只能消费一次,要想获取只能获得新的stream重新来一次
Stream<Dish> menuStream = menu.stream();
menuStream.forEach(dish -> System.out.println(dish.getName()));//采用forEach迭代操作
}
public static void main(String[] args) {
TestOne testOne = new TestOne();
testOne.doIt();
}
}
// system out
[french fries, rice, season fruit]
pork
beef
chicken
french fries
rice
season fruit
pizza
prawns
salmon

迭代

  1. for-each 迭代
1
2
3
4
List<String> names = new ArrayList<>();
for (Dish dish : menu) {
names.add(dish.getName());
}
  1. Iterator迭代
1
2
3
4
5
6
List<String> names = new ArrayList<>();
Iterator<Dish> iterator = menu.iterator();
while (iterator.hasNext()) {
Dish dish = iterator.next();
names.add(dish.getName());
}
1
2
3
List<String> names = menu.stream()
.map(Dish::getName)
.collect(toList());

使用流

总而言之,流的使用一般包括:

  • [x] 一个数据源(如集合)来执行一个查询操作,如List.stream();
  • [x] 一个中间操作链,形成一个水管从上游到下游的一系列操作,如filter、map、limit等。
  • [x] 一个终端操作,执行流水线操作,产生想要的结果,如 forEach、count 、collect等

操作符

  • filter

    顾名思义,就是做过滤筛选处理的。他会接受一个返回boolean的函数作为参数

1
2
3
menu.stream()
.filter(dish -> dish.getCalories()>300)//过滤calories>300的操作
.collect(toList());
  • distinct

    distinct根据元素对象的hashCode和equals方法实现去重操作

    1
    2
    3
    4
    5
    6
    List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 3, 2, 4);
    numList.stream()
    .filter(integer -> integer % 2 == 0) // 2 4 2 4
    .distinct() // 2 4
    .forEach(System.out::println);
    // 输出 2 4
  • limit

    流支持limit(n)限定操作,如果流失有序的,那么该操作最多会返回前n个元素。

1
2
3
4
5
6
7
8
List<String> collect = menu.stream()
.filter(Dish::isVegetarian)
.map(Dish::getName)
.limit(3)
.collect(toList());
System.out.println(collect);
//输出 [fries, rice, fruit]
  • skip

    流支持skip(n)操作,返回一个将前n个元素直接跳过的流,如果流中的元素不足n个,则返回一个空流,值得注意的的是skip和limit是互补的。

1
2
3
4
5
6
7
8
List<String> collect = menu.stream()
.filter(Dish::isVegetarian)
.map(Dish::getName)
.limit(3)
.skip(2)
.collect(toList());
System.out.println(collect);
//输出 [fruit]
  • map

    map操作符接受的是一个函数对象作为参数,他会将流发射的每一个信号元素进行转换成一个新的信号。

1
2
3
4
5
List<String> collect = menu.stream()
.map(Dish::getName)
.collect(toList());
System.out.println(collect);
// 输出 [pork, beef, chicken, fries, rice, fruit, pizza, prawns, salmon]
1
2
3
4
5
6
7
List<Integer> collect = menu.stream()
.map(Dish::getName)
.map(String::length)
.collect(toList());
System.out.println(collect);
//输出[4, 4, 7, 5, 4, 5, 5, 6, 6]
//流的链式处理接收的为上一个流操作的处理结果
  • flatMap

    map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。还有一些场景,是一对多映射关系的,这时需要 flatMap。flatMap操作符让你吧流中的每个值都换成另一个流,然后把所有的流连起来成为一个流

1
2
3
4
5
6
7
8
9
10
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(1),
Arrays.asList(2, 3),
Arrays.asList(4, 5, 6)
);
List<Integer> integerList = inputStream
.flatMap((childList) -> childList.stream())
.collect(toList());
System.out.println(integerList);
//输出[1, 2, 3, 4, 5, 6]
  • anyMatch—至少一个满足条件

    检查流中是否有一个元素能够匹配anyMatch中的给定元素,该操作返回一个boolean。只要返回的结果有一个达到满足的条件则认定该满足条件。他是一个最终结果操作不是中间操作,

1
2
3
4
boolean b = menu.stream()
.anyMatch(Dish::isVegetarian);
System.out.println(b);
// 输出 true
  • allMatch –所有满足条件

    allMatch跟anyMatch类似,他会判定流中的元素是否都能满足allMatch给定的参数

    1
    2
    3
    4
    boolean b = menu.stream()
    .allMatch(Dish::isVegetarian);
    System.out.println(b);
    // 输出 false
  • noneMatch —所有不满足条件

    noneMatch和allMatch对立,他会判定流中的元素是否都不能满足noneMatch给定的参数

    1
    2
    3
    4
    boolean b = menu.stream()
    .noneMatch(Dish::isVegetarian);
    System.out.println(b);
    // 输出 false
  • findAny

    他返回一个Optional类,待研究。。。

  • findFirst

    有些流我们需要找到操作的第一个元素,findFirst是一个不错的方法。

1
2
3
4
5
6
7
8
menu.stream()
.map(dish1 -> dish.getCalories())
.filter(f -> f > 300)
.findFirst()
.ifPresent(d-> {
System.out.println(d);
});
//输出 530

下班啦!!!