一.Java里面对Stream的定义:
A sequence of elements supporting sequential and parallel aggregate operations.
支持顺序和集合并行操作的一系列元素。
(1)Stream是元素的集合,类似于Iterator,单向,不可往复,数据只能遍历一次,遍历过一次数据即用尽了
(2)Stream 可以并行化操作,迭代器只能命令式地、串行化操作;
(3)Stream 的另外一大特点是,数据源本身可以是无限的。
二.创建Stream
1.通过Stream接口的静态工厂方法:
(1)of方法;
(2) generate方法;
(3)iterate方法;
import java.util.function.Supplier; import java.util.stream.Stream; public class NewStream { public static void main(String[] args) { //第一种 of方法; int shuzu[] = {4, 5, 6, 7, 8}; Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5); integerStream.forEach(System.out::println); Stream<String> stringStream = Stream.of("taobao", "weixin", "baidu", "toutiao"); stringStream.forEach(System.out::println); Stream.of(shuzu).forEach(System.out::println); //第二种 generate方法 Stream.generate(new Supplier<Double>() { @Override public Double get() { return Math.random(); } }).limit(10).forEach(System.out::println); //第三种 iterate方法 Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println); } }
2.通过collection的子类来获取Stream(Collection接口有一个Stream方法,所以其所有子类都可以获取对应的Stream对象。)
List list = new ArrayList(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.stream().forEach(System.out::println); LinkedList linkedList = new LinkedList(); linkedList.add(6); linkedList.add(7); linkedList.add(8); linkedList.add(9); linkedList.add(10); //并行流 linkedList.parallelStream().forEach(System.out::println); Set hashSet = new HashSet(); hashSet.add(11); hashSet.add(12); hashSet.stream().forEach(System.out::println);
三 .Stream操作
操作类型 | 接口方法 | |
Intermediate (中间操作) | 无状态(Stateless) | map(mapToInt、mapToLong、flatmap、mapToDouble、 flatMapToInt、flatMapToLong、flatMapToDouble)、unordered、filter、 peek、 parallel 、sequential 、isParallel |
有状态(Stateful) | distinct、 sorted、limit、 skip | |
Terminal (最终操作) | 非短路操作 | forEach、forEachOrdered、 toArray、 reduce、collect、 max、min、count、 |
Short-circuiting (短路操作) | anyMatch、allMatch、noneMatch、findFirst、 findAny |
中间操作和结束操作:
中间操作只是一种标记,结束操作才会触发实际计算;
中间操作后可以跟随其他操作,可以进行多次中间操作,结束操作执行后Stream元素就被消费掉了,无法对一个Stream进行两次terminal操作。
中间操作又可以分为无状态的(Stateless)和有状态的(Stateful),无状态的中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果,filter是无状态操作,符合过滤条件就被选出来,不关注其他元素的状态;
结束操作又可以分为短路操作和非短路操作,短路操作是指不用处理全部元素就可以返回结果,比如找到第一个满足条件的元素。
1.map()和flatMap()使用
map():将提供的函数应用于流的元素的结果
flatmap():将提供的流处理函数应用于流元素后获得的流元素
2.filter()使用
filter():根据传入的表达式,筛选出符合条件的元素
// 过滤不为null的元素 结果1 2 3 4 5 6 7 8 9 Stream.of(1, 2, 3, 4, 5, null, 6, null, 7, null, 8, 9). filter(integerStreams -> integerStreams != null).forEach(System.out::println);
3.unordered()使用
4.forEach()和peek()使用
forEach()和peek()方法都可以接收一个Lambda表达式,然后在Stream的每个元素上执行该表达式。
不同的是:
forEach是terminal操作。peek是一个intermediate操作,可以多次操作Stream。
import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class ForeachAndPeek { public static void main(String[] args) { Stream a = Stream.of("one", "two", "three", "four"); /* * forEach对于流来说是terminal操作,a第一次forEach后,就被"消费"掉了,所以第二次forEach就会报错 */ a.forEach(System.out::println); //a.forEach(System.out::println); //Stream.of("one", "two", "three", "four").forEach(System.out::println).forEach(System.out::println); //这是两个不同的流去执行forEach操作,所以不会报错 Stream.of("one", "two", "three", "four").forEach(System.out::println); Stream.of("one", "two", "three", "four").forEach(p -> System.out.println(p)); /* * peek操作不是terminal操作,而是intermediate操作。所以可以多次操作Stream */ Stream b = Stream.of("one", "two", "three", "four"); /* * Stream b已经被操作或者被消费掉了,已经没有Stream b了,会报错。 * 报错信息:stream has already been operated upon or closed */ //b.peek(System.out::println); //可以用一个新的Stream接收,再操作新的Stream Stream c = b.peek(System.out::println).peek(p -> System.out.println(p)); c.peek(System.out::println); /* * peek操作的用法 */ List streamList = Stream.of("one", "two", "three", "four"). filter(e -> e.length() > 3).peek(e -> System.out.println("Filtered value: " + e)). map(String::toUpperCase). peek(e -> System.out.println("Mapped value: " + e)).collect(Collectors.toList()); System.out.println(streamList); } }
5.sequential()和parallel()和isParallel()的使用:
sequential()是将并行流转化称串行流。parallel是将串行流转化成并行流。
isParallel判断是否为并行执行,输出结果为true和false。
List<Integer> list = new ArrayList<>(); for (int i=1;i<=10;i++){ list.add(i); } list.stream().parallel().forEach(a->System.out.print(a+",")); System.out.println(); list.parallelStream().sequential().forEach(a->System.out.print(a+",")); System.out.println(); System.out.println("==================="); System.out.println(list.stream().isParallel()); System.out.println(list.parallelStream().isParallel()); System.out.println(list.stream().parallel().isParallel()); System.out.println(list.parallelStream().sequential().isParallel());
输出结果为:
可以看出来,.parallel()输出的结果为乱序,.sequential() 方法输出的结果为顺序输出。
6.distinct()和count()使用
distinct():去重操作,输出结果为已经删除了重复元素的流元素;
count():返回流的元素个数;
public class distinct { public static void main(String[] args) { List list = new ArrayList(); list.add(1); list.add("2"); list.add(3L); list.add(1L); list.add(4L); list.add(3L); list.stream().forEach((a)-> System.out.print(a+ " ")); System.out.println( "count:"+list.stream().count()); list.stream().distinct().forEach((a)-> System.out.print(a+ " ")); System.out.println( "count:"+list.stream().distinct().count()); } }
输出结果如下:
7.sorted()使用
sorted():将数据按自然顺序进行排序。
sorted(Comparator<T>):将数据按提供的比较符进行排序。
8.limit()和skip()的使用
limit(long) 返回 Stream 的前面long个元素;
skip(long)丢弃了Stream的前面long个元素;
public class SkipAndLimit { public static void main(String[] args) { List list = new ArrayList<>(); list.add(1); list.add(2); list.add(5); list.add(6); list.add(3); list.add(4); list.add(7); list.add(8); list.add(9); list.add(6); list.add(3); list.add(4); list.stream().limit(3).forEach(System.out::print); System.out.println(); System.out.println("~~~~~~~"); list.stream().skip(3).forEach(System.out::print); } }
输出结果集如下:
9.forEach()和forEachOrdered()使用
forEach是并行处理的;
forEachOrdered是按顺序处理的。
所以forEach效率会略高一点。
package Stream; import java.util.Arrays; import java.util.List; public class ForEachAndForEachOrdered { public static void main(String[] args) { List<String> list = Arrays.asList("Two","Three","One","Four","Five"); list.stream().forEach(p->System.out.print(p+" ")); System.out.println("。"); list.stream().forEachOrdered(p->System.out.print(p+" ")); System.out.println("。"); //每次打印输出顺序是不一致的。 list.parallelStream().forEach(p->System.out.print(p+" ")); System.out.println("。"); list.parallelStream().forEachOrdered(p->System.out.print(p+" ")); System.out.println("。"); } }
10.toArray()使用
11.reduce()使用
reduce:将流的元素聚合为一个汇总值。
public class Reduce { public static void main(String[] args) { // 字符串连接,concat = "ABCD" String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat); System.out.println(concat); // 求最小值,minValue = -3.0 double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min); System.out.println(minValue); // 求和,sumValue = 1009, 有起始值(起始值+Sum(-1+1+2+3+4)) int sumValue = Stream.of(-1, 1, 2, 3, 4).reduce(1000, Integer::sum); System.out.println(sumValue); // 求和,sumValue = 10, 无起始值 sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get(); System.out.println(sumValue); // 过滤,字符串连接,concat = "BDF" concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") < 0).reduce("", String::concat); System.out.println(concat); } }
12.collect()使用
collect():将流的元素聚合到一个汇总结果容器中。
List<Integer> list = Stream.of(1,2,3,4,5,6,7,8,9).collect(Collectors.toList());
13.max()和min()使用
max()返回流中最大的值;
min()返回流中最小的值;
这几种方式都是可以的:
package Stream; import java.util.Comparator; import java.util.stream.Stream;public class MaxAndMin { public static void main(String[] args) { int a = Stream.of(-99, -100, 3, 5, 9, 99).max(Integer::compare).get();//99 int b = Stream.of(-99, -100, 3, 5, 9, 99).min(Integer::compare).get();//-100 int c = Stream.of(-99, -100, 3, 5, 9, 99).max((n, m) -> Integer.compare(n, m)).get();//99 int d = Stream.of(-99, -100, 3, 5, 9, 99).min((n, m) -> Integer.compare(n, m)).get();//-100 int e = Stream.of(-99, -100, 3, 5, 9, 99).max(Comparator.comparing(Integer::valueOf)).get();//99 int f = Stream.of(-99, -100, 3, 5, 9, 99).min(Comparator.comparing(Integer::valueOf)).get();//-100 int j = Stream.of(-99, -100, 3, 5, 9, 99).mapToInt(i -> i).max().getAsInt();//99 int l = Stream.of(-99, -100, 3, 5, 9, 99).mapToInt(i -> i).min().getAsInt();//-100 System.out.println("a:"+a); System.out.println("b:"+b); System.out.println("c:"+c); System.out.println("d:"+d); System.out.println("e:"+e); System.out.println("f:"+f); System.out.println("j:"+j); System.out.println("l:"+l); } }
输出结果如下:
还有一种经典的错误demo,这种方式是不可行的:
因为stream().max()是以返回值的正数,负数和0来判断大小的
public static void main(String[] args) { //错误的用法 int g = Stream.of(-99,-100,3,5,9,99).max(Integer::max).get(); int h = Stream.of(-99,-100,3,5,9,99).min((v,k) -> { int result = Integer.max(v, k); return result; }).get(); System.out.println("g:"+g); System.out.println("h:"+h); }
14.allMatch(),anyMatch()和noneMatch()的使用
allMatch:Stream中全部元素符合传入的条件返回true;
anyMatch:Stream中有一个元素符合传入的条件就返回true;
noneMatch:Stream中没有一个元素符合传入的条件返回true;
List<Integer> list = new ArrayList<>(); for (int i=1;i<=10;i++){ list.add(i); } list.stream().forEach(System.out::println); System.out.println("全部大于9:"+list.stream().allMatch(a->a>9)); System.out.println("全部大于0:"+list.stream().allMatch(a->a>0)); System.out.println("有一个及以上大于9:"+list.stream().anyMatch(a->a>9)); System.out.println("有一个及以上大于10:"+list.stream().anyMatch(a->a>10)); System.out.println("没有一个大于9:"+list.stream().noneMatch(a->a>9)); System.out.println("没有一个大于10:"+list.stream().noneMatch(a->a>10));
输出结果为:
15.findFirst()和findAny()的使用
findFirst()返回第一个元素,如果流为空,则返回一个空Optional。
findAny()返回任意一个元素,如果流为空,则返回一个空Optional。对于并行流来说可能多次返回结果不一致,但是性能会略优秀于findFirst()。
public class FindFirstAndDFindAny { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); List<Integer> list2 = new ArrayList<>(); for (int i = 1; i <= 10000; i++) { list.add(i); } System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findAny()); System.out.println(list.parallelStream().findFirst()); System.out.println(list2.parallelStream().findFirst()); } }
结果如下:
可以看出多次执行并行流的findAny操作,结果是不一样的。