流的简单使用
Integer[] nums = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(nums);
// 过滤掉 不是 > 2 的,并统计元素数量
long count = list.stream().filter(n -> n > 2).count();
System.out.println(count);
// 上面过程的并行版
count = list.parallelStream().filter(n -> n > 2).count();
System.out.println(count);
流的获取
Integer[] nums = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(nums);
// 1、将 Collection 转为 Stream
// Collection 接口下的 stream 和 parallelStream 方法 可以返回一个 Stream
Stream<Integer> stream = list.stream();
// 并行流,后续操作会以并行方式运行
Stream<Integer> stream1 = list.parallelStream();
// 2、Steam.of 方法直接传入对象
// public static<T> Stream<T> of(T... values)
// 这里如果传入 基本类型的数组的话, int[] ,泛型对不上,nums 会作为 int[] 类型的一个参数被传递
Stream<Integer> stream2 = Stream.of(nums);
stream2.forEach(System.out::println); // [I@11096447
stream2 = Stream.of(1, 2, 3, 6);
// 产生一个不包含任何元素的流
Stream.empty();
// 产生一个无限长度的流,每个结果由参数中的函数过程生成的返回值
stream2 = Stream.generate(() -> 1);
// 如产生一个随机数流
Random random = new Random();
stream2 = Stream.generate(random::nextInt);
stream2 = Stream.generate(() -> random.nextInt(100));
// 产生一个无限长度的流,设置一个初始结果,每次生成的结果会作为下一次生产过程的参数
// 如产生一个自增流
stream2 = Stream.iterate(0, n -> ++n);
Stream<BigInteger> stream22 = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
// 3、将数组转换为 Stream
// Arrays.stream 方法
// 产生一个 从起始下标,到结束下标(不包括结束下标)的流
Stream<Integer> stream3 = Arrays.stream(nums, 0, 4);
// 还有其他很多 类都自带产生流的 方法 如 Pattern.splitAsStream 、 Files.lines
流的转换
将流做一些处理并返回一个流
Integer[] nums = {1, 2, 3, 4, 5};
Stream<Integer> stream = Arrays.stream(nums);
// 流操作一次后不能再次操作,这里不用 stream 重新接收新的流的话,后面再次操作会报错错
// stream.filter(n -> n > 2);
// 过滤,将返回 true 的结果作为新的流返回
stream=stream.filter(n -> n > 2);
// 对每个元素进行操作,将传入的函数应用到每个元素上,函数的返回值作为每个元素的新值
stream=stream.map(n->n*10);
Stream<String> stringStream=Stream.of("what","is","your","name");
// flatMap 将流里的每个元素都转换为流,再将这些流 合成为一个流返回
stringStream.flatMap(w->{
char[] chars = w.toCharArray();
List<Character> list=new ArrayList<>();
for(Character c:chars)list.add(c);
return list.stream();
}).forEach(System.out::print);
抽取子流和连接流
Integer[] nums = {1, 2, 3, 4, 5 ,6 ,7, 8};
Stream<Integer> stream = Arrays.stream(nums);
// 截取流的 前 n 个元素,作为新的流返回
stream=stream.limit(4); // 1 2 3 4
// 丢弃前 n 个元素,将剩余的元素作为新流返回
stream=stream.skip(2); // 3 4 1234跳过前两个剩下34
// 生成一个 有 100 个随机数的流
Stream.generate(Math::random).limit(1000);
Stream<Integer> stream2 = Arrays.stream(nums);
Stream<Integer> stream3 = Arrays.stream(nums);
// 拼接两个流 ,第一个流不应该是无限的,否则第二个流始终用不到,没有意义
stream=Stream.concat(stream2,stream3); // 1.2.3···8.1.2.3···8
// 去重,返回一个去掉重复元素的流
stream.distinct();
stream.forEach(System.out::println);
流的转换 2
// 流排序
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// 调用 sorted 方法获得一个经过排序的流
stream=stream.sorted();
// 传入 比较器 ,传入了一个逆序的比较器,做逆序
stream=stream.sorted(Comparator.comparing(n->(Integer)n).reversed());
// 返回一个流,并且当这个流取出元素的时候,会先执行这里的函数过程
stream=stream.peek(e-> System.out.print("本次使用的元素是"+e+"---"));
// 这里 调用 forEach 会取出元素,每次取出元素会先输出 本次使用的元素是X 在执行这里的过程
// 如果没有调用forEach ,也就是没有取出元素,你会发现 peek 方法中的函数过程并不会执行
stream.forEach(System.out::print); // 本次使用的元素是9---9本次使用的元素是8---8本次使用的元素是7---7 ···
简单约简 ,终结流的操作,将流转为非流值
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// 获取流元素数
long counts=stream.count();
stream = Arrays.stream(nums);
// 获取流元素中最大的 (min方法与之用法相同)
Optional<Integer> max = stream.max(Integer::compare);
// 获得实际值,参数是当获取不到的时候的默认值
Integer iMax = max.orElse(0);
stream = Arrays.stream(nums).filter(n->n>6);
// 返回第一个匹配的元素
Optional<Integer> first = stream.findFirst();
stream = Arrays.stream(nums).filter(n->n>6);
// 返回任何一个匹配元素,在并行处理流的时候比较有效
Optional<Integer> any = stream.findAny();
boolean b;
// 是否全部匹配
b=Arrays.stream(nums).allMatch(n->n>1); // false
// 是否存在匹配
b=Arrays.stream(nums).anyMatch(n->n>2); // true
// 是否没有匹配
b=Arrays.stream(nums).noneMatch(n->n>10);// true
System.out.println(b);
Optional 类型
Long[] nums = {6L,3L,1L,4L,5L,3L,9L,7L,6L,4L,2L,1L,8L};
Stream<Long> stream = Arrays.stream(nums);
// stream 的一些方法会返回一个包含结果的 Optional 对象
Optional<Long> first = stream.filter(n -> n > 6L).findFirst();
Long l;
// 获得Optional中的值 ,如果没有则返回 传入的 替代物
l=first.orElse(0L);
// 当没有值的时候 还可以调用代码获取替代值,(只有在需要替代值的时候才会调用代码)
l=first.orElseGet(()-> new Date().getTime());
// 当没有值的时候 抛出异常
//l= first.orElseThrow(Exception::new);
// 只有当值存在的时候 调用
first.ifPresent(System.out::println);
// 将结果值处理并包装返回
// 如果 first 有值,返回包装处理结果的 Optional ,
// 如果 first 没有值,返回空的 Optional(是没有值的一个 Optional 对象,不是返回 null)
Optional<Integer> aBoolean = first.map((n) -> n==9?1:2);
// 返回 Optional 中的值,没有值的时候会抛异常,不推荐用
first.get();
// 返回一个 boolean 表示是否有值
first.isPresent();
/// 创建 Optional 的方法
// 产生一个 Optional 对象,如果 传入的是 null 会抛异常
Optional<Integer> integer = Optional.of(2);
// 产生一个 Optional 对象,如果传入的是 null 会返回一个没有值的 Optional 对象
Optional<Object> o = Optional.ofNullable(null);
// 产生一个没有值的 Optional 对象
Optional<Object> empty = Optional.empty();
// 将值 处理,并包装成 Optional 并返回
Optional<String> s = first.flatMap(m -> Optional.ofNullable(m.toString()));
收集结果-流转集合
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// 获取 Iterator 来遍历流中的元素
Iterator<Integer> iterator = stream.iterator();
// 遍历每个元素并应用函数
// 在并行流上是没有顺序的
Arrays.stream(nums).parallel().forEach(System.out::print); // 9674421358316 9674331126458 9673216445138
// 会按顺序遍历,但是会导致并行处理的性能优势基本丧失
Arrays.stream(nums).parallel().forEachOrdered(System.out::print);
// 获得由流元素组成的数组
Object[] objects = Arrays.stream(nums).toArray();
// 传入数组构造器,来获得正确的数组类型
Integer[] integers = Arrays.stream(nums).toArray(Integer[]::new);
// 获取流元素组成的 集合,可以传入 集合的构造器
TreeSet<Integer> collect2 = Arrays.stream(nums).collect(Collectors.toCollection(TreeSet::new));
// 获取流元素组成的 List
List<Integer> collect = Arrays.stream(nums).collect(Collectors.toList());
// 获取流元素组成的 Set
Set<Integer> collect1 = Arrays.stream(nums).collect(Collectors.toSet());
// 产生一个整型的对象收集器(收集过程中可以处理元素),利用收集器可以获得 平均、 最大、最小、总和、结果个数
// 有对应的 long double 版本
IntSummaryStatistics summaryStatistics = Arrays.stream(nums).collect(Collectors.summarizingInt(n -> n));
summaryStatistics.getAverage();
summaryStatistics.getCount();
summaryStatistics.getMax();
summaryStatistics.getMin();
summaryStatistics.getSum();
String[] words = {"zs","ls","ww"};
Stream<String> wordsStream = Arrays.stream(words);
// 可以将 流中的字符串拼接
String collect3 = wordsStream.collect(Collectors.joining());
// 设置分隔符
wordsStream.collect(Collectors.joining(","));
// 设置分隔符 ,前缀,后缀
wordsStream.collect(Collectors.joining(",","^","$"));
收集到映射表中 Steam 转 Map
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// 流转为 Map ,第一参数是 map 键的获取过程,第二个参数是 map 值的获取过程 ,如果键冲突会抛异常
//Map<Integer, String> map = stream.collect(Collectors.toMap(n -> n, n -> n.toString()));
// 第三个参数,指明当键冲突的时候,可以如何处理旧值(原来存在的值)和新值,作为此键对应的值
Map<Integer, String> map2 = Arrays.stream(nums).collect(Collectors.toMap(n -> n, n -> n.toString(),(oldValue,newValue)->oldValue));
// 转并发线程安全的 map
// ConcurrentMap<Integer, String> concurrentMap = Arrays.stream(nums).collect(Collectors.toConcurrentMap(n -> n, n -> n.toString()));
// 将元素分组,每组保存 到 list 中
Map<String, List<Integer>> collect = Arrays.stream(nums).collect(Collectors.groupingBy(n -> n>2?"大于2":"小于等于2"));
System.out.println(collect); // {大于2=[6, 3, 4, 5, 3, 7, 9, 6, 4, 8], 小于等于2=[1, 2, 1]}
// 取得并发线程安全 map 版
Map<String, List<Integer>> collect2 = Arrays.stream(nums).collect(Collectors.groupingByConcurrent(n -> n>2?"大于2":"小于等于2"));
System.out.println(collect2); // {大于2=[6, 3, 4, 5, 3, 7, 9, 6, 4, 8], 小于等于2=[1, 2, 1]}
// 如果只分两组,可以使用以 boolean 为键的版本,其效率要 比 groupingBy 高
Map<Boolean, List<Integer>> collect1 = Arrays.stream(nums).collect(Collectors.partitioningBy(n -> n > 2 ? true : false));
System.out.println(collect1); // {false=[1, 2, 1], true=[6, 3, 4, 5, 3, 7, 9, 6, 4, 8]}
下游收集器, groupingBy 的后续
收集到 Map, groupingBy 的扩展,可对收集到的 list 做进一步转换
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// toSet() :对 收集到的 map list 型 值,转换成 set
Map<String, Set<Integer>> collect = stream.collect(Collectors.groupingBy(n -> n > 2 ? "大于2" : "小于等于2", Collectors.toSet()));
System.out.println(collect); // {大于2=[3, 4, 5, 6, 7, 8, 9], 小于等于2=[1, 2]}
// summingInt: 对 收集到的 map 各个list 型值 ,分别求各个list中的元素 和 , 这个例子 就是对 大于 2和 小于2 的分别求和 返回到一个 map
// summingInt 还有对应 double long 版本
// a->a 这里是将 list 中的数据转成 int 型的过程,因为本来list中的元素就是 int 型,所以不做任何处理返回, 也可以使用 Function.identity() 同样的效果
Map<String, Integer> collect1 = Arrays.stream(nums).collect(Collectors.groupingBy(n -> n > 2 ? "大于2" : "小于2", Collectors.summingInt(a -> a)));
System.out.println(collect1); // {小于2=4, 大于2=55}
// counting :对 收集到的 map 各个list 型值 ,分别求各个list中的元素 数目
Map<String, Long> collect2 = Arrays.stream(nums).collect(Collectors.groupingBy(n -> n > 2 ? "大于2" : "小于2", Collectors.counting()));
System.out.println(collect2); // {小于2=3, 大于2=10}
// 对 收集到的 map 各个list 型值 ,分别求各个list中的元素 最大元素 对应还有 minBy
Map<String, Optional<Integer>> collect3 = Arrays.stream(nums).collect(Collectors.groupingBy(n -> n > 2 ? "大于2" : "小于2", Collectors.maxBy(Integer::compare)));
System.out.println(collect3); // {小于2=Optional[2], 大于2=Optional[9]}
// mapping
// 对 收集到的 map 各个list 型值 ,分别对各个list中的元素做一层处理后,再交给后续的 Collectors
Map<String, List<String>> collect4 = Arrays.stream(nums).collect(
Collectors.groupingBy(n -> n > 2 ? "大于2" : "小于2",
Collectors.mapping(n -> "c"+n.toString(),
Collectors.mapping(n->n,Collectors.toList()))));
System.out.println(collect4); // {小于2=[c1, c2, c1], 大于2=[c6, c3, c4, c5, c3, c7, c9, c6, c4, c8]}
约简操作 Stream.reduce
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// reduce :和 ConCurrentHashMap.reduce 类似
// 将前一次的处理结果作为参数,参与下一次处理
// 即 result = v1 op v2 op v3 op v4 ···· op 必须满足 ,x op y op z = x op ( y op z )
// op 例 : 求和,乘积,字串拼接,max,min,并集,交集···
Optional<Integer> reduce = stream.reduce((x, y) -> x + y);
// 第一个参数为 幺元 e , 幺元满足 e op v = v
// 当流为 null ,会返回 幺元
Integer reduce1 = Arrays.stream(nums).reduce(0, (x, y) -> x + y);
System.out.println(reduce1);
// 第一个参数为 幺元
// 第二个参数为 op
// 第三个参数为,多线程将 不同分组的结果 合并的方式(内部使用了 fork-join框架)
String reduce2 = Arrays.stream(nums).reduce("x", (x, y) -> x +"-"+ y.toString(), (x, y) -> x +"*" +y);
System.out.println(reduce2); // x-6-3-1-4-5-3-7-9-6-4-2-1-8
String reduce4 = Arrays.stream(nums).parallel().reduce("x", (x, y) -> x +"-"+ y.toString(), (x, y) -> x +"*" +y);
System.out.println(reduce4); // x-6*x-3*x-1*x-4*x-5*x-3*x-7*x-9*x-6*x-4*x-2*x-1*x-8
Integer reduce3 = Arrays.stream(new String[]{"zs", "ls", "zll"}).parallel().reduce(0, (a, b) -> a + b.length(), (a, b) -> +a + b);
System.out.println(reduce3); // 7
基本类型流
// 将基本类型包装成对象使用,效率会降低,可以使用基本类型专属的流,以int为例
int[] nums={1,6,8,9,7,6};
IntStream intStream = IntStream.of(1, 3, 6, 4, 9, 8);
IntStream stream = Arrays.stream(nums);
OptionalInt first = stream.findFirst();
OptionalInt max = stream.max();
IntSummaryStatistics intSummaryStatistics = stream.summaryStatistics();
intSummaryStatistics.getSum();
intSummaryStatistics.getMax();
intSummaryStatistics.getAverage();
intSummaryStatistics.getCount();
// 产生步长为 1 的流 ,int 和 lang 专有 ,包括 10
IntStream range = IntStream.range(1, 10);
range.forEach(System.out::print);
// 不包括 10
IntStream range2 = IntStream.rangeClosed(1, 10);
range2.forEach(System.out::print);
int[] ints = stream.toArray();
// 产生包装器对象流
Stream<Integer> boxed = stream.boxed();
并行流的获取
Integer[] nums = {6,3,1,4,5,3,7,9,6,4,2,1,8};
Stream<Integer> stream = Arrays.stream(nums);
// 产生一个 与当前 stream 元素相同的 并行流
Stream<Integer> parallel = stream.parallel();
// 产生一个 与当前 stream 元素相同 的无序流
stream.unordered();
Collection collection=new ArrayList();
collection.stream();
// 根据当前集合产生一个 并行流
collection.parallelStream();
网友评论