stream的使用
- stream特点
- stream和parallelStream的区别
- filter 过滤(中间操作)
- forEach 对流进行遍历(终止操作)
- limit 按给定长度截断流(中间操作)
- map和flatMap将函数作用于每个元素(中间操作)
- allMatch 流中所有元素都满足条件(终止操作)
- anyMatch 流中是否有元素满足条件(终止操作)
- noneMatch 流中没有元素满足条件(终止操作)
- count 返回流的大小(终止操作)
- distinct 去除重复元素(中间操作)
- findFirst 返回流的第一个元素(终止操作)
- findAny 返回流中任意一个元素(终止操作)
- concat 拼接两个流
- generate 根据提供的方法,持续生成流
- iterate 指定种子进行迭代
- max和min根据提供的比较函数返回此流的最大|小元素
- peek 将流中元素作用于函数(中间操作)
- skip 跳过元素(中间操作)
- reduce 将流中元素结合起来得到一个值(终止操作)
- toArray将流中元素封装成数组(终止操作)
- sorted 对流中元素进行排序(中间操作)
- empty返回一个空的流
- of 返回其元素是指定值的顺序排序流
- builder 返回stream构造器
数据集合
ArrayList<Person> list = new ArrayList<>(10);
list.add(new Person().setId(0).setAge(10).setName("a"));
list.add(new Person().setId(1).setAge(11).setName("b"));
list.add(new Person().setId(2).setAge(12).setName("c"));
list.add(new Person().setId(3).setAge(13).setName("d"));
list.add(new Person().setId(4).setAge(14).setName("e"));
list.add(new Person().setId(5).setAge(15).setName("f"));
list.add(new Person().setId(6).setAge(16).setName("g"));
list.add(new Person().setId(7).setAge(17).setName("h"));
list.add(new Person().setId(8).setAge(18).setName("i"));
list.add(new Person().setId(9).setAge(19).setName("j"));
stream特点
- Stream不调用终止方法,中间的操作不会执行。
stream和parallelStream的区别
-
stream 是顺序流,由主线程按顺序对流执行操作。
-
parallelStream 是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。
示例代码:
list.parallelStream().forEach(System.out::println);
System.out.println(("----------"));
list.stream().forEach(System.out::println);
运行结果:
Person(id=6, age=16, name=g)
Person(id=5, age=15, name=f)
Person(id=8, age=18, name=i)
Person(id=2, age=12, name=c)
Person(id=1, age=11, name=b)
Person(id=7, age=17, name=h)
Person(id=4, age=14, name=e)
Person(id=3, age=13, name=d)
Person(id=9, age=19, name=j)
Person(id=0, age=10, name=a)
----------
Person(id=0, age=10, name=a)
Person(id=1, age=11, name=b)
Person(id=2, age=12, name=c)
Person(id=3, age=13, name=d)
Person(id=4, age=14, name=e)
Person(id=5, age=15, name=f)
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
filter 过滤(中间操作)
示例代码:
list.stream().filter(person -> person.getId() > 5).forEach(System.out::println);
运行结果:
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
- 满足条件的元素通过(true),不满足条件的元素会被丢弃(false)
forEach 对流进行遍历(终止操作)
示例代码:
list.stream().forEach(System.out::println); // 方法引用
运行结果:
Person(id=0, age=10, name=a)
Person(id=1, age=11, name=b)
Person(id=2, age=12, name=c)
Person(id=3, age=13, name=d)
Person(id=4, age=14, name=e)
Person(id=5, age=15, name=f)
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
示例代码:
list.stream().forEach(person -> System.out.print(person.getId()));
运行结果:
0123456789
limit 按给定长度截断流(中间操作)
示例代码:
list.stream().limit(5L).forEach(System.out::println);
运行结果:
Person(id=0, age=10, name=a)
Person(id=1, age=11, name=b)
Person(id=2, age=12, name=c)
Person(id=3, age=13, name=d)
Person(id=4, age=14, name=e)
map和flatMap将函数作用于每个元素(中间操作)
map和flatMap的区别
flatMap所用映射函数返回值必须为Stream,会将返回的Stream展开并集合起来重新串成一个新的Stream。
map所用映射函数可返回任意类型元素,直接将返回元素串起来形成一个新的Stream。
示例代码:
list.stream().flatMap(person -> {
ArrayList<Person> append = new ArrayList<>(2);
append.add(person);
append.add(new Person().setId(person.getId() + 10));
return append.stream();
}).forEach(System.out::println);
System.out.println("------------------");
list.stream().map(person -> {
ArrayList<Person> append = new ArrayList<>(2);
append.add(person);
append.add(new Person().setId(person.getId() + 10));
return append.stream();
}).forEach(System.out::println);
运行结果:
Person(id=0, age=10, name=a)
Person(id=10, age=0, name=null)
Person(id=1, age=11, name=b)
Person(id=11, age=0, name=null)
Person(id=2, age=12, name=c)
Person(id=12, age=0, name=null)
Person(id=3, age=13, name=d)
Person(id=13, age=0, name=null)
Person(id=4, age=14, name=e)
Person(id=14, age=0, name=null)
Person(id=5, age=15, name=f)
Person(id=15, age=0, name=null)
Person(id=6, age=16, name=g)
Person(id=16, age=0, name=null)
Person(id=7, age=17, name=h)
Person(id=17, age=0, name=null)
Person(id=8, age=18, name=i)
Person(id=18, age=0, name=null)
Person(id=9, age=19, name=j)
Person(id=19, age=0, name=null)
------------------
java.util.stream.ReferencePipeline$Head@6a5fc7f7
java.util.stream.ReferencePipeline$Head@3b6eb2ec
java.util.stream.ReferencePipeline$Head@1e643faf
java.util.stream.ReferencePipeline$Head@6e8dacdf
java.util.stream.ReferencePipeline$Head@7a79be86
java.util.stream.ReferencePipeline$Head@34ce8af7
java.util.stream.ReferencePipeline$Head@b684286
java.util.stream.ReferencePipeline$Head@880ec60
java.util.stream.ReferencePipeline$Head@3f3afe78
java.util.stream.ReferencePipeline$Head@7f63425a
示例代码:
System.out.println(list.stream().map(person -> 10).collect(Collectors.toList()));
System.out.println(list.stream().map(person -> "hello").collect(Collectors.toList()));
运行结果:
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
[hello, hello, hello, hello, hello, hello, hello, hello, hello, hello]
mapToInt 函数返回值必须为int类型
flatMapToInt 函数返回值必须为IntegerSteam类型
mapToDouble 函数返回值必须为double类型
flatMapToDouble 函数返回值必须为DobuleSteam类型
mapToLong 函数返回值必须为long类型
flatMapToLong 函数返回值必须为LongStream类型
allMatch 流中所有元素都满足条件(终止操作)
示例代码:
System.out.println(list.stream().allMatch(person -> person.getId() == 5));
System.out.println(list.stream().allMatch(person -> person.getId() != 11));
输出结果:
false
true
anyMatch 流中是否有元素满足条件(终止操作)
示例代码:
System.out.println(list.stream().anyMatch(person -> person.getAge() == 11));
System.out.println(list.stream().anyMatch(person -> person.getAge() == 1));
运行结果:
true
false
noneMatch 流中没有元素满足条件(终止操作)
示例代码:
System.out.println(list.stream().noneMatch(person -> person.getId() == 5));
System.out.println(list.stream().noneMatch(person -> person.getId() == 15));
运行结果:
false
true
count 返回流的大小(终止操作)
示例代码:
System.out.println(list.stream().count());
输出结果:
10
distinct 去除重复元素(中间操作)
示例代码:
List<Integer> integerList = Arrays.asList(1, 2, 3, 3, 4, 4, 5, 6);
System.out.println(integerList.stream().distinct().collect(Collectors.toList()));
运行结果:
[1, 2, 3, 4, 5, 6]
findFirst 返回流的第一个元素(终止操作)
示例代码:
Optional<Person> optionalPerson = list.stream().findFirst();
optionalPerson.ifPresent(System.out::println);
输出结果:
Person(id=0, age=10, name=a)
findAny 返回流中任意一个元素(终止操作)
findAny操作,返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。使用findAny()是为了更高效的性能。如果是数据较少,串行地情况下,一般会返回第一个结果,如果是并行的情况,那就不能确保是第一个。
示例代码:
Optional<Person> optionalPerson = list.parallelStream().findAny();
optionalPerson.ifPresent(System.out::println);
运行结果:
Person(id=6, age=16, name=g)
concat 拼接两个流
示例代码:
ArrayList<Person> list2 = new ArrayList<>(2);
list2.add(new Person().setId(10).setAge(20).setName("k"));
list2.add(new Person().setId(11).setAge(21).setName("l"));
Stream<Person> stream = Stream.concat(list.stream(), list2.stream());
stream.forEach(System.out::println);
运行结果:
Person(id=0, age=10, name=a)
Person(id=1, age=11, name=b)
Person(id=2, age=12, name=c)
Person(id=3, age=13, name=d)
Person(id=4, age=14, name=e)
Person(id=5, age=15, name=f)
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
Person(id=10, age=20, name=k)
Person(id=11, age=21, name=l)
generate 根据提供的方法,持续生成流
示例代码:
// 如果没有limit,控制台将持续打印生成的随机数。
Stream.generate(Math::random).limit(5).forEach(System.out::println);
Stream<Double> generateB = Stream.generate(()-> Math.random()).limit(5).forEach(System.out::println);
Stream<Double> generateA = Stream.generate(new Supplier<Double>() {
@Override
public Double get() {
return Math.random();
}
}).limit(5).forEach(System.out::println);
// 三者等价,Supplier为函数接口
运行结果:
0.5137198806722759
0.6204101302224982
0.2502610330633914
0.32596750750752745
0.4628503400128364
iterate 指定种子进行迭代
示例代码:
Stream.iterate(1, item -> item + 1).limit(10).forEach(item -> System.out.print(item + "\t"));
运行结果:
1 2 3 4 5 6 7 8 9 10
示例代码:
Stream.iterate('a', item -> (char)(item + 1)).limit(10).forEach(item -> System.out.print(item + "\t"));
运行结果:
a b c d e f g h i j
max和min根据提供的比较函数返回此流的最大|小元素
示例代码:
Optional<Person> optionalPerson = list.stream().max((t1, t2) -> {
return Integer.compare(t1.getAge(), t2.getAge());
});
optionalPerson.ifPresent(System.out::println);
// 等价于
Optional<Person> optionalPerson = list.stream().max(Comparator.comparingInt(Person::getAge));
// 比较结果返回值
// 返回负整数,零或正整数,因为第一个参数小于,等于或大于第二个参数
(t1 < t2) ? -1 : ((t1 == t2) ? 0 : 1);
运行结果:
Person(id=9, age=19, name=j)
示例代码:
Optional<Person> optionalPerson = list.stream().min(Comparator.comparingInt(Person::getAge));
optionalPerson.ifPresent(System.out::println);
运行结果:
Person(id=0, age=10, name=a)
peek 将流中元素作用于函数(中间操作)
示例代码:
list.stream().peek(person -> person.setId(0)).forEach(System.out::println);
运行结果:
Person(id=0, age=10, name=a)
Person(id=0, age=11, name=b)
Person(id=0, age=12, name=c)
Person(id=0, age=13, name=d)
Person(id=0, age=14, name=e)
Person(id=0, age=15, name=f)
Person(id=0, age=16, name=g)
Person(id=0, age=17, name=h)
Person(id=0, age=18, name=i)
Person(id=0, age=19, name=j)
skip 跳过元素(中间操作)
示例代码:
list.stream().skip(5).forEach(System.out::println);
运行结果:
Person(id=5, age=15, name=f)
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
reduce 将流中元素结合起来得到一个值(终止操作)
方法一:
示例代码:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
stream.reduce((item1, item2) -> {
System.out.println("item1:" + item1 + " item2:" + item2);
return item1 + item2;
}).ifPresent(System.out::print);
// 返回值为optional类型
运行结果:
item1:1 item2:2
item1:3 item2:3
item1:6 item2:4
item1:10 item2:5
item1:15 item2:6
item1:21 item2:7
item1:28 item2:8
item1:36 item2:9
45
方法二:
示例代码:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(stream.reduce(10, (item1, item2) -> {
System.out.println("item1:" + item1 + " item2:" + item2);
return item1 + item2;
}));
// 第一个参数必须于stream中元素的类型相同。返回值为相同元素类型
运行结果:
item1:10 item2:1
item1:11 item2:2
item1:13 item2:3
item1:16 item2:4
item1:20 item2:5
item1:25 item2:6
item1:31 item2:7
item1:38 item2:8
item1:46 item2:9
55
方法三:
示例代码:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
ArrayList<Integer> integers = new ArrayList<>();
System.out.println(stream.reduce(integers, (array, item) -> {
System.out.println("array:" + array + " item:" + item);
array.add(item);
return array;
}, (item1, item2) -> null));
// 返回值类型可以自定义
运行结果:
array:[] item:1
array:[1] item:2
array:[1, 2] item:3
array:[1, 2, 3] item:4
array:[1, 2, 3, 4] item:5
array:[1, 2, 3, 4, 5] item:6
array:[1, 2, 3, 4, 5, 6] item:7
array:[1, 2, 3, 4, 5, 6, 7] item:8
array:[1, 2, 3, 4, 5, 6, 7, 8] item:9
[1, 2, 3, 4, 5, 6, 7, 8, 9]
第三个参数定义的规则并没有执行。这是因为reduce的第三个参数是在使用parallelStream的reduce操作时,合并各个流结果的,本例中使用的是stream,所以第三个参数是不起作用的。
toArray将流中元素封装成数组(终止操作)
示例代码:
System.out.println(list.stream().toArray());
for (Object o : list.stream().toArray()) {
System.out.println(o);
}
System.out.println(list.stream().toArray(Person[]::new));
for (Person person : list.stream().toArray(Person[]::new)) {
System.out.println(person);
}
运行结果:
[Ljava.lang.Object;@880ec60
Person(id=0, age=10, name=a)
Person(id=1, age=11, name=b)
Person(id=2, age=12, name=c)
Person(id=3, age=13, name=d)
Person(id=4, age=14, name=e)
Person(id=5, age=15, name=f)
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
[Lstream.Person;@36d64342
Person(id=0, age=10, name=a)
Person(id=1, age=11, name=b)
Person(id=2, age=12, name=c)
Person(id=3, age=13, name=d)
Person(id=4, age=14, name=e)
Person(id=5, age=15, name=f)
Person(id=6, age=16, name=g)
Person(id=7, age=17, name=h)
Person(id=8, age=18, name=i)
Person(id=9, age=19, name=j)
sorted 对流中元素进行排序(中间操作)
示例代码:
Stream<Integer> stream1 = Stream.generate(() -> new Random().nextInt(10)).limit(10);
Stream<Integer> stream2 = stream1.peek(item -> System.out.print(item + "\t"));
stream2.sorted().forEach(item -> System.out.print(item + "\t"));
// stream2.sorted(Integer::compareTo).forEach(item -> System.out.print(item + "\t"));
运行结果:
4 3 8 9 6 0 7 8 9 1 0 1 3 4 6 7 8 8 9 9
empty返回一个空的流
Stream<Person> stream = Stream.empty();
of 返回其元素是指定值的顺序排序流
Stream<Integer> stream1 = Stream.of(1, 2, 3);
Stream<Integer> stream2 = Stream.of(1);
builder 返回stream构造器
// 创建一个流构造器
Stream.Builder<Integer> sb = Stream.builder();
sb.accept(10);
sb.add(11);
// 构造流
Stream<Integer> stream1 = sb.build();
stream1.forEach(System.out::println);
- 流构造之后就不能使用其accept和add方法,否则会报错。