[Java1.8]_[Stream]
来源:互联网 发布:java源码阅读工具 编辑:程序博客网 时间:2024/05/16 12:41
Java 8 Stream教程
Stream不同于之前的I/O流,而是Java 8引入的函数式编程。
函数式编程
简单说,”函数式编程”是一种”编程范式”(programming paradigm),也就是如何编写程序的方法论。
它属于”结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
Stream 简单例子
用一个遍历数组的例子看看Stream的作用。
传统写法
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");List<String> newList = new ArrayList<String>();//遍历for (String name : myList){ //筛选出字母开头是c的 if (name.startsWith("c")) { //转换成大写 String newName = name.toUpperCase(); newList.add(newName); }}//排列Collections.sort(newList);//遍历输出newList.forEach(System.out::println);
Stream写法
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");myList .stream() //开始流操作 .filter(s -> s.startsWith("c")) //筛选出开头字母是C的 .map(String::toUpperCase) //转换成大写 .sorted() //排序 .forEach(System.out::println); //遍历输出//C1//C2
Stream操作这里有用到Lambda表达式,大多数的Steam操作都可以用Lamdba表达式。Stream操作简化了很多,主要体现在逻辑清晰,没有过多的if/else判断语句。
Stream的种类
Stream分为sequential Stream(顺序流)和parallel stream(平行流),上面的例子是属于顺序流,通过stream()方法创建的流都是顺序流。
Stream
一般的集合如List和Set都支持Stream操作,但可以不通过创建集合来使用Stream操作,可以通过Stream.of()方法使用,代码如下:
Stream.of("a1", "a2", "a3") .findFirst() .ifPresent(System.out::println); // a1
Primitive streams
Stream是处理对象的操作,primitive streams是处理处理传统类型的操作,如IntStream、LongStream 、DoubleStream分别处理对应的类型,这里展示InStream的简单使用:
IntStream.range(1, 4) .forEach(System.out::println);// 1// 2// 3
Primitive streams和Streams的使用基本一样,只是有一些专门处理基本类型的方法,像上面的range(),还有如下例子:
Arrays.stream(new int[] {1, 2, 3}) .map(n -> 2 * n + 1) .average() .ifPresent(System.out::println); // 5.0
average() 方法求平均值,Primitive streams和Stram都有方法讲对象和基本类型互相转换,代码如下:
Stream.of(1.0, 2.0, 3.0) .mapToInt(Double::intValue) .mapToObj(i -> "a" + i) .forEach(System.out::println);// a1// a2// a3
Stream操作的顺序
先看下面例子代码:
Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> { System.out.println("filter: " + s); return true; });
该例子实际上是不会输出任何东西,因为Stream没有终端操作,只有中间操作。
再看看加入终端操作后的结果:
Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> { System.out.println("filter: " + s); return true; }) .forEach(s -> System.out.println("forEach: " + s));
输出结果:
filter: d2forEach: d2filter: a2forEach: a2filter: b1forEach: b1filter: b3forEach: b3filter: cforEach: c
这里的输出结果可能会让你觉得很诧异,是数组元素按顺序执行完整个流操作,即要第一个元素执行完整个流操作才轮到第二个。
我们可以将元素重新排序然后再执行流操作,通过sort()方法,代码如下:
Stream.of("d2", "a2", "b1", "b3", "c") .sorted((s1, s2) -> { System.out.printf("sort: %s; %s\n", s1, s2); return s1.compareTo(s2); }) .filter(s -> { System.out.println("filter: " + s); return s.startsWith("a"); }) .map(s -> { System.out.println("map: " + s); return s.toUpperCase(); }) .forEach(s -> System.out.println("forEach: " + s));
输出结果:
sort: a2; d2sort: b1; a2sort: b1; d2sort: b1; a2sort: b3; b1sort: b3; d2sort: c; b3sort: c; d2filter: a2map: a2forEach: A2filter: b1filter: b3filter: cfilter: d2
Reusing Streams
Java 8的Stream不能被重复使用直到该Stream已经结束,其实Stream可以返回一个实例,看实例代码:
Stream<String> stream = Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> s.startsWith("a"));stream.anyMatch(s -> true); // okstream.noneMatch(s -> true); // exception
该结果会出现异常,因为stream的anyMatch()方法还没执行完就执行noneMatch(),异常如下:
java.lang.IllegalStateException: stream has already been operated upon or closed at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229) at java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:459) at com.winterbe.java8.Streams5.test7(Streams5.java:38) at com.winterbe.java8.Streams5.main(Streams5.java:28)
可以通过创建Supplier来实现重复执行,代码例子如下:
Supplier<Stream<String>> streamSupplier = () -> Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> s.startsWith("a"));streamSupplier.get().anyMatch(s -> true); // okstreamSupplier.get().noneMatch(s -> true); // ok
较为复杂的Stream操作
前面只是举例说明了一下,常用的map()、filter()、foreach()等操作很容易看明白,还有很多操作可以看这个链接
Java stream doc。
首先创建一个Person类方便说明,如下:
class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name; }}List<Person> persons = Arrays.asList( new Person("Max", 18), new Person("Peter", 23), new Person("Pamela", 23), new Person("David", 12));
Collect
Collect可以在最后将结果转化成一个集合返回,代码如下:
List<Person> filtered = persons .stream() .filter(p -> p.name.startsWith("P")) .collect(Collectors.toList());System.out.println(filtered); // [Peter, Pamela]
可以看到还是比较简单实用的,通过Collectors.toList()方法直接返回一个List,如果需要set就用toSet(),
使用非常方便。
还可以生成Map指点类集合和求平均值,代码例子分别如下:
Map<Integer, String> map = persons .stream() .collect(Collectors.toMap( p -> p.age, p -> p.name, (name1, name2) -> name1 + ";" + name2));System.out.println(map);
Double averageAge = persons .stream() .collect(Collectors.averagingInt(p -> p.age));System.out.println(averageAge); // 19.0
FlatMap
如果集合或数组的元素本身也是集合或数组,而且我们就是要求访问集里面的集合的时候就要用到FlatMap,代码例子如下:
class Foo { String name; List<Bar> bars = new ArrayList<>(); Foo(String name) { this.name = name; }}class Bar { String name; Bar(String name) { this.name = name; }}
foos.stream() .flatMap(f -> f.bars.stream()) .forEach(b -> System.out.println(b.name));// Bar1 <- Foo1// Bar2 <- Foo1// Bar3 <- Foo1// Bar1 <- Foo2// Bar2 <- Foo2// Bar3 <- Foo2// Bar1 <- Foo3// Bar2 <- Foo3// Bar3 <- Foo3
Reduce
Reduce的作用就是将流操作的多个结果汇集成一个,例子如下:
Person result = persons .stream() .reduce(new Person("", 0), (p1, p2) -> { p1.age += p2.age; p1.name += p2.name; return p1; });System.out.format("name=%s; age=%s", result.name, result.age);
parallel stream
parallelStream不同于Stream的地方是它会让中间流操作利用ForkJoinPool的线程进行操作,而使用的线程是不确定的,代码例子如下:
Arrays.asList("a1", "a2", "b1", "c2", "c1") .parallelStream() .filter(s -> { System.out.format("filter: %s [%s]\n", s, Thread.currentThread().getName()); return true; }) .map(s -> { System.out.format("map: %s [%s]\n", s, Thread.currentThread().getName()); return s.toUpperCase(); }) .sorted((s1, s2) -> { System.out.format("sort: %s <> %s [%s]\n", s1, s2, Thread.currentThread().getName()); return s1.compareTo(s2); }) .forEach(s -> System.out.format("forEach: %s [%s]\n", s, Thread.currentThread().getName()));
输出结果:
filter: b1 [main]filter: a1 [ForkJoinPool.commonPool-worker-3]filter: a2 [ForkJoinPool.commonPool-worker-1]map: a2 [ForkJoinPool.commonPool-worker-1]filter: c1 [ForkJoinPool.commonPool-worker-2]forEach: A2 [ForkJoinPool.commonPool-worker-1]map: a1 [ForkJoinPool.commonPool-worker-3]map: b1 [main]forEach: A1 [ForkJoinPool.commonPool-worker-3]filter: c2 [ForkJoinPool.commonPool-worker-1]map: c1 [ForkJoinPool.commonPool-worker-2]map: c2 [ForkJoinPool.commonPool-worker-1]forEach: B1 [main]forEach: C2 [ForkJoinPool.commonPool-worker-1]forEach: C1 [ForkJoinPool.commonPool-worker-2]
- [Java1.8]_[Stream]
- leetcode500 Java1.8 Stream
- Stream:java1.8新特性
- Stream:java1.8新特性
- Java1.8新特性 Lambda/Stream/函数式编程
- [Java1.8]_[Built-in Functional Interfaces]
- java1.8一个不错的api调用栈(1)从Stream<?>创建一个Map
- 【工作笔记】java1.8新特性之stream初使用:list分组、实体转换、求和
- Java1.8新特性关于lambda表达式与Stream流的使用以及对集合的实用操作
- java1.8 版本改成 java1.7版本
- Java1~8"新特性"
- Java1.8环境变量配置
- centos7安装java1.8
- java1.8--Optional类
- JAVA1.8新特性
- Condition java1.8
- centos7安装java1.8
- Java1.8集合
- 小鑫の日常系列故事(十)——排名次
- VS2012中使用Link.exe手动链接obj
- 图解js原型(原型,对象,函数之间的关系)
- LeetCode No.219 Contains Duplicate II
- spark sql
- [Java1.8]_[Stream]
- 二叉树查找
- AJAX进阶应用
- ubuntu设置环境变量
- NYOJ 290动物统计加强版(Trie树)
- Hash Tables 哈希表
- POJ4001/HDU4121 Xiangqi 大模拟
- Android 网络框架_网络框架的核心Http协议
- matlab 中画箭头