引言:
Java8新特性
Java8新特性2
新特性概览
Lambda
表达式
- 函数式接口
- 方法引用与构造器的引用与数组引用
- Stream API
1、2、3、请看 Java8新特性1
强大的StreamAPI
Stream 流:
是一个数据渠道,可以对数据源(集合、数组)的数据进行一系列的操作。
(集合讲的是数据,流讲的是计算)
注意:
- Stream 不会存储元素
- Stream 不会改变源操作对象
- Stream 是延迟执行的,等到需要的结果出现后才会执行
步骤:
- 创建Stream
- 中间操作
- 终止操作(中断操作)

创建Stream流的四种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ArrayList<String> strings = new ArrayList<>(); Stream<String> stream = strings.stream();
Integer[] integers = new Integer[10]; Stream<Integer> stream1 = Arrays.stream(integers);
Stream<Integer> stream2 = Stream.of(integers);
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2);
stream3.limit(10);
Stream<Double> generate = Stream.generate(() -> Math.random()); generate.limit(10);
|
Stream的中间操作
筛选与切片:
fiter
——接收lambda,从流中排除某些元素
limit
——截断流,使其元素不超过给定的数量
skip(n)
——跳过元素,返回一个去除了前n个元素的流。若流元素不足n个,则返回一个空流,与limit(n)互补
distinct
——筛选,通过流所生成的元素的hashCode()和equals()去除重复元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
Stream<Student> studentStream = students .stream() .filter(x -> { System.out.println("中间操作"); return x.getAge() > 30; });
studentStream.forEach(System.out::println);
Stream<Student> stream1 = students.stream().limit(2); stream1.forEach(System.out::println);
Stream<Student> stream2 = students.stream().skip(2); stream2.forEach(System.out::println);
Stream<Student> stream3 = students.stream().distinct(); stream3.forEach(System.out::println);
|
映射
map
——接收一个lambda,将元素转换为其他形式或提取信息。提取一个函数作为参数,该函数会被应用到每一个元素上,并将其映射为一个新的元素。
flatMap
——接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连接成一个流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| List<String> strings = Arrays.asList("aaa", "bbb", "ccc"); Stream<String> stream1 = strings.stream() .map(x -> x.toUpperCase());
stream1.forEach(System.out::println);
System.out.println("-------flatMap------");
Function<String,Stream> fun = (x) -> strings.stream();
Stream stream2 = strings .stream() .flatMap(fun::apply); stream2.forEach(System.out::println); System.out.println("--------map---------");
Stream stream3 = strings .stream() .map(fun::apply); stream3.forEach( System.out::println);
|
运行结果如下:
排序
排序:
sorted()
——自然排序(Comparable),按照字典序
sorted(Comparator com)
——定制排序(Comparator)
排序操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| List<String> strings = Arrays.asList("ccc", "bbb", "aaa"); strings.stream().sorted().forEach(System.out::println);
students.stream() .sorted((e1,e2)->{ if(e1.getAge().equals(e2)){ return e1.getName().compareTo(e2.getName()); }else { return e1.getAge().compareTo(e2.getAge()); } }) .distinct() .forEach(System.out::println);
|
终止操作
查找与匹配:
查找与匹配操作:
allMatch
——是否匹配所有元素
anyMatch
——是否至少匹配一个元素
noneMatch
—— 是否没有匹配所有元素
findFirst
——返回第一个元素,返回值是一个Optional
对象,该对象可以防止为null
findAny
——返回当前流中的任意元素
count
——返回流中元素的总个数
max
——返回流中最大值
min
——返回流中最小值
数据:
1 2 3 4 5 6 7 8
| List<Student> students = Arrays.asList( new Student("李白",15), new Student("杜甫",27), new Student("白居易",96), new Student("孟浩然",77), new Student("孟浩然",77), new Student("孟浩然",77) );
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| boolean b1 = students.stream() .allMatch(x -> x.getAge().equals(27)); System.out.println(b1);
boolean b2 = students.stream() .anyMatch(x -> x.getAge().equals(27)); System.out.println(b2);
boolean b3 = students.stream() .noneMatch(x -> x.getAge().equals(27)); System.out.println(b3);
Optional<Student> first = students.stream().sorted((e1, e2) -> { return -e1.getAge().compareTo(e2.getAge()); }).findFirst();
System.out.println(first);
Optional<Student> any = students.parallelStream().findAny(); System.out.println(any);
long count = students.stream().count();
Optional<Student> max = students.stream().max((e1, e2) -> { return e1.getAge().compareTo(e2.getAge()); }); System.out.println(max);
|
归约与收集
归约:
reduce(T identity, BinaryOperator)
reduce(BinaryOperator)
可以将流中的元素反复结合起来得到一个值。
1 2 3 4 5
| Optional<Integer> reduce = students.stream() .map(Student::getAge) .reduce(Integer::sum); System.out.println(reduce.get());
|
map-reduce
组合常用在大数据当中
收集:
collect
——将流转换为其他形式,接收一个Collector
接口的实现,用于给Stream
中元素做汇总的方法
1 2 3 4 5 6 7 8 9 10 11 12
| List<String> collect = students .stream() .map(Student::getName) .collect(Collectors.toList()); collect.forEach(System.out::println);
HashSet<String> collect1 = students.stream() .map(Student::getName) .collect(Collectors.toCollection(HashSet::new)); collect1.forEach(System.out::println);
|
收集还有很多种方式,可以求最大最小等等,这里不再细说。
并行流
并行流:
将一个内容分为多个数据块,使用不同的线程分别处理每个数据块的流,并且含有工作窃取,即一个核对应的任务完成后,会从其他核偷取任务来执行,大大提高了执行效率
使用parallel
切换为并行流
使用sequential
切换为串行流
在之前有一个ForkJoin
框架,这个框架就实现了对一个任务的拆分与合并,大大提高了处理速度。
在Java8之后我们可以使用并行流来处理(底层其实还是ForkJoin框架)
1 2 3 4 5 6
| Instant start = Instant.now(); LongStream.range(0,100000000000L) .parallel() .reduce(0,Long::sum); Instant end = Instant.now(); System.out.println(Duration.between(start,end).toMillis());
|
运算一千亿个数循环相加,用时12s,下图可见我的CPU利用率基本占满