zoukankan      html  css  js  c++  java
  • Stream(Java 8)

    Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
    它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。

    前言

    Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次。
    
    流的构成:
    	获取一个数据源(source)→ 数据转换 → 执行操作获取想要的结果。
    	每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换)。
    
    
    转换操作是lazy(惰性求值,只能迭代一次):
    
    	只有在Terminal操作执行时,才会一次性执行。
    
    	Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中。
    
    	在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
    

    构造流的几种常见方法

    1. Individual values
    
    	Stream stream = Stream.of("a", "b", "c");
    
    2. Arrays
    
    	String [] strArray = new String[]{"a", "b", "c"};
    	stream = Stream.of(strArray);
    	stream = Arrays.stream(strArray);
    
    3. Collections
    
    	List<String> list = Arrays.asList(strArray);
    	stream = list.stream();
    
    文件生成流:
    	Stream<String> stream = Files.lines(Paths.get("data.txt"));
    

    流转换为其它数据结构

    1. Array
    
    	String[] strArray1 = stream.toArray(String[]::new);
    
    2. Collection
    
    	List<String> list1 = stream.collect(Collectors.toList());
    	List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
    	Set set1 = stream.collect(Collectors.toSet());
    	Stack stack1 = stream.collect(Collectors.toCollection(Stack::new));
    
    3. String
    
    	String str = stream.collect(Collectors.joining()).toString();
    

    流的操作

    当把一个数据结构包装成 Stream 后,就要开始对里面的元素进行各类操作了。常见的操作可以归类如下。
    
    
    中间操作:
    	Intermediate(主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流)
    
    	map(mapToInt, flatMap)、 
    	filter、 distinct、 sorted、 
    	peek、 limit、 skip、 parallel、 sequential、 unordered
    
    	.filter(person -> person.getAge() == 20)	过滤器
    
    	.distinct()	去除重复元素,这个方法是通过类的 equals 方法来判断两个元素是否相等的
    
    	.sorted()(流中的元素的类实现了 Comparable 接口) / sorted((p1, p2) -> p1.getAge() - p2.getAge())	排序
    	.sorted(Comparator.comparingInt(Person::getAge))
    
    	.limit(long n)	返回前 n 个元素
    
    	.skip(long n)	去除前 n 个元素
    
    	.map(T -> R)	将流中的每一个元素 T 映射为 R(类似类型转换)
    	.map(Person::getName)
    
    	.flatMap(T -> Stream<R>)	将流中的每一个元素 T(数组) 映射为一个流,再把每一个流连接成为一个流
    	.flatMap(Arrays::stream)
    
    
    结束操作:
    	Terminal(流的最后一个操作)
    
    	forEach、 forEachOrdered、 
    	toArray、 reduce、 collect、 min、 max、 
    	count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
    
    	boolean b = list.stream().anyMatch(person -> person.getAge() == 20);	判断是否有匹配条件的元素
    
    	.allMatch(T -> boolean)	是否所有元素都符合匹配条件
    
    	.reduce((T, T) -> T) 和 reduce(T, (T, T) -> T)	用于组合流中的元素,如求和,求积,求最大值等
    	.reduce(0, Integer::sum)
    	reduce 第一个参数 0 代表起始值为 0
    
    	.count()	返回流中元素个数,结果为 long 类型
    
    	.collect()	收集方法
    
    		最常用的方法,把流中所有元素收集到一个 List Set Collection 中
    
    			toList()
    			toSet()
    			toCollection()
    			toMap()
    
    		joining() 连接字符串
    
    		counting()	计算总和
    

    数值流

    Stream<Integer> 类型,而每个 Integer 都要拆箱成一个原始类型再进行 sum 方法求和,这样大大影响了效率。
    
    针对这个问题 Java 8 有良心地引入了数值流 IntStream, DoubleStream, LongStream。
    
    
    三种对应的包装类型 Stream:
    
    	IntStream、LongStream、DoubleStream
    
    IntStream.of(new int[]{1, 2, 3}).forEach(System.out::println);
    
    IntStream.range(1, 3).forEach(System.out::println);	半开区间[)
    
    IntStream.rangeClosed(1, 3).forEach(System.out::println);	闭区间[]
    
    
    流转换为数值流:
    	mapToInt(T -> int) : return IntStream
    	mapToDouble(T -> double) : return DoubleStream
    	mapToLong(T -> long) : return LongStream
    
    数值流转换为流:
    	Stream<Integer> stream = intStream.boxed();
    
    数值流方法:
    	sum()
    	max()
    	min()
    	average()
    

    并行流(必须是线程安全的)

    Stream.of(list).parallel();
    

    无限长度的流

    generator:
    	generator方法,返回一个无限长度的Stream,其元素由Supplier接口的提供。
    
    	在Supplier是一个函数接口,只封装了一个get()方法,其用来返回任何泛型的值。
    
    		- generate(Supplier<T> s):返回一个无限长度的Stream
    
    		示例:
    		
    		1. Stream<Double> generateA = Stream.generate(new Supplier<Double>() {
    		     @Override
    		     public Double get() {
    		         return Math.random();
    		     }
    		   });
    		
    		2. Stream<Double> generateB = Stream.generate(()->Math.random());
    		3. Stream<Double> generateC = Stream.generate(Math::random);
    		
    iterate
    	iterate方法,其返回的也是一个无限长度的Stream。
    
    	与generate方法不同的是,其是通过函数f迭代对给指定的元素种子而产生无限连续有序Stream,
    	其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。
    		
    		- iterate(T seed, UnaryOperator<T> f)
    		
    		示例:
    		
    			Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);
    			      // 打印结果:1,2,3,4,5,6,7,8,9,10 
    		
    			上面示例,种子为1,也可认为该Stream的第一个元素,
    			通过f函数来产生第二个元素。
    			接着,第二个元素,作为产生第三个元素的种子,从而产生了第三个元素,
    			以此类推下去。
    			需要注意的是,该Stream也是无限长度的,
    			应该使用filter、limit等来截取Stream,否则会一直循环下去。
    
  • 相关阅读:
    第16章 行为型模式—命令模式
    第15章 行为型模式—职责链模式
    第14章 结构型模式—代理模式
    第12章 结构型模式—外观模式
    第11章 结构型模式—装饰模式
    第10章 结构型模式—组合模式
    第9章 结构型模式—桥接模式
    第8章 结构型模式—适配器模式
    Qt中Qstring,char,int,QByteArray之间到转换(转)
    QT:QByteArray和QByteArray、char *(转)
  • 原文地址:https://www.cnblogs.com/loveer/p/11764945.html
Copyright © 2011-2022 走看看