Stream: 流水线
流水线 : 对数据的一组操作
jdk8,添加了新的类java.util.Stream:
Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利高效的聚合操作,或者大批量数据操作
Stream的API结合Lambda表达式,极大的提高编程效率和程序可读性
同时它提供串行和并行两种模式进行操作
-
使用流
流的使用一般包括三件事: 1,一个数据源(如集合)来执行一组操作; 2,一个中间操作链,形成一条流的流水线; 3,一个终端操作,执行流水线,并能生成结果。 4,Stream对象的构建 1.使用值构建 Stream<String> stream = Stream.of("a", "b", "c"); 2. 使用数组构建 String[] strArray = new String[] {"a", "b", "c"}; Stream<String> stream = Stream.of(strArray); Stream<String> stream = Arrays.stream(strArray); 3. 利用集合构建(不支持Map集合) List<String> list = Arrays.asList(strArray); stream = list.stream(); 注:基本数据类型的流:IntStream ,LongStream,DoubleStream 不要选用Stream<Integer>,Stream<Long>,Stream<Double>因为自动装箱耗时,效率低 Java 8 中还没有提供其它基本类型数值的Stream 4,IntStream:数值Stream的构建: IntStream s1 = IntStream.of(new int[]{1, 2, 3}); //[1,3) IntStream s2 = IntStream.range(1, 3); //[1,3] IntStream s3 = IntStream.rangeClosed(1, 3);
-
Stream转换为其它类型:
Stream<String> stream = Stream.of("hello","world","tom"); 1,转换为Array String[] strArray = stream.toArray(String[]::new); 2,转换为Collection List<String> list1 = stream.collect(Collectors.toList()); List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new)); Set<String> set3 = stream.collect(Collectors.toSet()); Set<String> set4 = stream.collect(Collectors.toCollection(HashSet::new)); 3. 转换为String String str = stream.collect(Collectors.joining()).toString(); 注意 : 一个 Stream 只可以使用一次,上面的代码为了简洁而重复使用了多次。 这个代码直接运行会抛出异常的: java.lang.IllegalStateException: stream has already been operated upon or closed
-
流操作
java.util.stream.Stream中的Stream接口定义了许多操作。 它们可以分为两大类。 1,中间操作 : 可以连接起来的流操作 2,终端操作 : 关闭流的操作 终端操作会从流的流水线生成结果。 其结果是任何不是流的值,比如List Integer,甚至void。 注:除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。
-
中间操作 : Intermediate
map map(Function<? super T,? extends R> mapper) 返回由给定函数应用于此流的元素的结果组成的流。 eg:把 Stream中 的每一个元素,映射成另外一个元素 public static void main(String[] args) throws Exception { Stream<String> stream = Stream.of("tom","lisi","wangwu"); //R apply(T t); Function<String,String> fun = (t)->t.toUpperCase(); List<String> list = stream.map(fun).collect(Collectors.toList()); System.out.println(list); } filter : filter(Predicate<? super T> predicate) 返回由与此给定谓词匹配的此流的元素组成的流。 eg:获取字符串中长度大于3的字符串 public static void main(String[] args) throws Exception { Stream<String> stream = Stream.of("tom","lisi","wangwu","a"); List<String> list = stream.filter((msg)->msg.length()>3).collect(Collectors.toList()); // boolean test(T t); // Predicate<T> System.out.println(list); } peek : 偷看,可以用来检查流当前的状态。 (Consumer<? super T> action) 对每个元素执行操作并返回一个新的 Stream 注意:调用peek之后,一定要有一个最终操作 public static void main(String[] args) throws Exception { Stream<String> stream = Stream.of("tom","lisi","wangwu"); stream.filter(e -> e.length() > 3) .peek(e -> System.out.println("符合条件的值为: " + e)) .collect(Collectors.toList()); } distinct: 返回由不同元素组成的流 sorted: 返回由此流的元素组成的流,根据自然顺序排序。 sorted(Comparator<? super T> comparator) limit: limit(long maxSize) 限制流的长度不超过maxSize public static void main(String[] args) throws Exception { Stream<String> stream = Stream.of("tom","lisi","wangwu","hhhhhh","werwerwefwe"); stream.filter(e -> e.length() > 3) .peek(e -> System.out.println("符合条件的值为: " + e)).limit(2) .collect(Collectors.toList()); } 满足条件的有多个,但是最终返回的集合中只有两个数据。 skip: skip(long n); 跳过多少个元素 public static void main(String[] args) throws Exception { Stream<String> st = Stream.of("tom","lisi","wangwu","zhaoliu"); List<String> list = st.skip(2).collect(Collectors.toList()); System.out.println(list); } 最终打印[wangwu, zhaoliu] parallel : 并行 sequential : 有顺序
-
终端操作 : Terminal
forEach : 遍历 接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。 stream.forEach(System.out::println); findFirst : 总是返回 Stream 的第一个元素,或者空,返回值类型:Optional。 如果集中什么都没有,那么list.stream().findFirst()返回一个Optional<String>对象,但是里面封装的是一个null。 public static void main(String[] args) throws Exception { Stream<String> stream = Stream.of("hello","world","tom"); Optional<String> findFirst = stream.findFirst(); System.out.println(findFirst); } anyMatch : allMatch(Predicate<? super T> predicate) 任意一个匹配成功返回true allMatch: allMatch(Predicate<? super T> predicate) 所有匹配成功才返回true noneMatch : noneMatch(Predicate<? super T> predicate) 没有一个匹配的就返回true 否则返回false count:计数 返回Stream中元素的个数,返回值类型是long。 reduce :合并 允许通过指定的函数来将stream中的多个元素规约合并为一个元素. 它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max等都是特殊的 reduce。 eg1: 1-10累加 IntStream red = IntStream.range(1, 10); Integer sum = red.reduce(0, (a, b) -> a+b); System.out.println(sum); eg2: 拼接字符串 String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat); System.out.println(concat); eg3: List<String> list = Arrays.asList("test","javac","hello","world","java","tom","C","javascript"); Optional<String> reduce = list.stream().sorted((s1,s2)->s2.length()-s1.length()).filter(s->s.startsWith("j")).map(s->s+"_briup").reduce((s1,s2)->s1+"|"+s2); System.out.println(reduce.orElse("值为空")); //javascript_briup|javac_briup|java_briup max: max(Comparator<? super T> comparator) 根据提供的 Comparator返回此流的最大元素。 String[] arr= {"zom","lisi","wagnwu"}; Stream<String> stream = Arrays.stream(arr); Optional<String> max = stream.max(String::compareTo); System.out.println(max.get());//zom min: min(Comparator<? super T> comparator) 根据提供的 Comparator返回此流的最小元素。 String[] arr= {"zom","lisi","wagnwu"}; Stream<String> stream = Arrays.stream(arr); Optional<String> max = stream.min(String::compareTo); System.out.println(max.get());//lisi forEachOrdered: 如果流具有定义的遇到顺序,则以流的遇到顺序对该流的每个元素执行操作。 Stream<String> stream = Stream.of("tom","lisi"); stream.forEachOrdered((a)->{System.out.println(a);}); toArray : toArray(IntFunction<A[]> generator) 使用提供的 generator函数返回一个包含此流的元素的数组,以分配返回的数组,以及分区执行或调整大小可能需要的任何其他数组。 Stream<String> stream = Stream.of("tom","lisi"); String[] array = stream.toArray(String[]::new); collect : collect(Collector<? super T,A,R> collector) 使用 Collector对此流的元素执行 mutable reduction Collector 。 Stream<String> stream = Stream.of("tom","lisi"); List<String> list = stream.collect(Collectors.toList()); Set<String> set = stream.collect(Collectors.toSet()); findAny: 返回描述流的一些元素的Optional如果流为空,则返回一个空的Optional iterator: 获得迭代器 短路操作 : Short-circuiting: anyMatch allMatch noneMatch findFirst findAny limit 短路 - 短路操作潜在的允许对流的操作尽早停止,而不去检查所有的元素。这是对无限流的一个特殊设计的属性;如果对流的操作没有短路,那么代码可能永远也不会终止。 Stream.generate 自己来控制Stream的生成 这种情形通常用于随机数、常量的 Stream,或者需要前后元素间维持着某种状态信息的 Stream。 把 Supplier 实例传递给 Stream.generate() 生成的 Stream,由于它是无限的,在管道中,必须利用limit之类的操作限制Stream大小。 可以使用此方式制造出海量的测试数据 eg: 生成100个随机数并由此创建出Stream实例 Stream.generate(()->(int)(Math.random()*100)).limit(100).forEach(System.out::println); 工具类:Collectors java.util.stream.Collectors 类 主要作用就是辅助进行各类有用的操作。 eg1: 把Stream中的元素进行过滤然后再转为List集合 List<String> list = Arrays.asList("test","hello","world","java","tom","C","javascript"); List<String> result = list.stream().filter(s->s.length()>4).collect(Collectors.toList());
-
串行和并行:
串行Stream上的操作是在一个线程中依次完成
并行Stream则是在多个线程上同时执行串行和并行的相互转换: 可以通过对收集源调用parallelStream方法来把集合转换为并行流。 对顺序流调用parallel方法把流转换成并行流。 并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 对顺序流调用parallel方法并不意味着流本身有任何实际的变化。它在内部实际上就是设了一个boolean标志,表示你想让调用parallel之后进行的所有操作都并行执行。 只需要对并行流调用BaseStream下的sequential()方法就可以把它变成顺序流。 并行测试: public static void main(String[] args) { //生成100万个不同的字符串放到集合中 int max = 1000000; List<String> values = new ArrayList<String>(max); for (int i = 0; i < max; i++) { UUID uuid = UUID.randomUUID(); values.add(uuid.toString()); } //1纳秒*10^9=1秒 long t0 = System.nanoTime(); //串行stream long count = values.stream().sorted().count(); //并行stream //long count = values.parallelStream().sorted().count(); long t1 = System.nanoTime(); long time = t1 - t0; System.out.println(count); System.out.println(time); }