2018年10月22日
目录
Java 是面向对象语言,除了原始数据类型之处,Java 中的所有内容都是一个对象。而在函数式语言中,我们只需要给函数分配变量,并将这个函数作为参数传递给其它函数就可实现特定的功能。
一、Lambda
Lambda 表达式的加入,使得 Java 拥有了函数式编程的能力。在其它语言中,Lambda 表达式的类型是一个函数;但在 Java 中,Lambda 表达式被表示为对象,因此它们必须绑定到被称为功能接口的特定对象类型。
1.1 lambda小例子1
new Thread(() -> System.out.println("hello!!")).start();;
输出结果:
hello!!
点击“->”:
1.2 lambda小例子2
package LambdaTest;
public class Lambda2 {
interface ITest { //接口
int test(String string);
}
static void Print(ITest test) {//接口做对象
test.test("hello world");
}
public static void main(String [] args) {
Print(string -> {System.out.println(string);
return 0;}
);
}
}
运行结果:
hello world
1.3 分析
先来看lambda表达式的语法:
() -> {}
-
() : 括号就是接口方法的括号,接口方法如果有参数,也需要写参数。只有一个参数时,括号可以省略。(Thread的构造函数接收的是一个Runnable接口对象,而我们这里的用法相当于是把一个函数当做接口对象传递进去了,这点理解很关键,这正是函数式编程的含义所在。)
-
-> :这个箭头是lambda表达式的关键操作符,分割左右部分的,没啥好讲的,作用是:把表达式分成两截,前面是函数参数,后面是函数体。
-
{} : 要实现的方法体。只有一行代码时,可以不加括号,可以不写return。
-
我们注意到Runnable有个注解 @FunctionalInterface,它是jdk8才引入,它的含义是函数接口。它是lambda表达式的协议注解,这个注解非常重要,后面做源码分析会专门分析它的官方注释,到时候一目了然。
二、Stream
2.1 如何理解Stream
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。
简单来说,它的作用就是通过一系列操作将数据源(集合、数组)转化为想要的结果。
2.2 Stream特点
Stream 是不会存储元素的。
Stream 不会改变原对象,相反,他们会返回一个持有结果的新Stream。
Stream 操作是延迟执行的。意味着它们会等到需要结果的时候才执行。
2.3 生成Stream的方式
下面是五种生成stream方法:
//1. Collection系的 stream() 和 parallelStream();
ArrayList<Object> list = new ArrayList<>();
Stream<Object> stream = list.stream();
Stream<Object> stringStream = list.parallelStream();
//2. 通过Arrays
Stream<String> stream1 = Arrays.stream(new String[10]);
//3. 通过Stream
Stream<Integer> stream2 = Stream.of(1,2,3);
//4. 无限流,迭代
Stream<Integer> iterate = Stream.iterate(0, (x) -> x+22);
iterate.limit(10).forEach(System.out::println);
//5. 生成
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.forEach(System.out::println);
2.4 Stream的中间操作
//和map差不多,但返回类型为Stream,类似list.add()和list.addAll()的区别
// arrayList.stream().map(s -> s+1).forEach(System.out::println);
arrayList.stream()
.map(s -> s + 1) //映射
.flatMap(s -> Stream.of(s))
.filter(s -> s < 1000) //过滤
.limit(5) //限制
.skip(1) //跳过
.distinct() //去重
.sorted() //自然排序
.sorted(Integer::compareTo) //自定义排序
;
多个中间操作连接而成为流水线,流水线不遇到终止操作是不触发任何处理的,所为又称为“惰性求值”。
关于map方法,参数为一个Function函数型接口的对象,也就是传入一个参数返回一个对象。这个参数就是集合中的每一项。类似Iterator遍历。其它的几个操作思想都差不多。
执行上面的方法没什么用,因为缺少终止操作。
2.5 Stream的终止操作
1.stream常用api
// 返回流中元素的总个数
System.out.println(arrayList.stream().count());
arrayList.stream().allMatch((x) -> x == 555); // 检查是否匹配所有元素
arrayList.stream().anyMatch(((x) -> x>600)); // 检查是否至少匹配一个元素
arrayList.stream().noneMatch((x) -> x>500); //检查是否没有匹配所有元素
arrayList.stream().findFirst(); // 返回第一个元素
arrayList.stream().findAny(); // 返回当前流中的任意一个元素
arrayList.stream().count(); // 返回流中元素的总个数
arrayList.stream().forEach(System.out::println); //内部迭代
arrayList.stream().max(Integer::compareTo); // 返回流中最大值
Optional<Integer> min = arrayList.stream().min(Integer::compareTo);//返回流中最小值
System.out.println("min "+min.get());
2.reduce (归约):将流中元素反复结合起来得到一个值
Integer reduce = arrayList.stream()
.map(s -> (s + 100))
.reduce(0, (x, y) -> x + y);
//归约:0为第一个参数x的默认值,x是计算后的返回值,y为每一项的值。
System.out.println(reduce);
Optional<Integer> reduce1 = arrayList.stream()
.map(s -> (s + 1))
.reduce((x, y) -> x + y);
// x是计算后的返回值,默认为第一项的值,y为其后每一项的值。
System.out.println(reduce1);
3.collect(收集):将流转换为其他形式。需要Collectors类的一些方法。
Set<Integer> collect = arrayList.stream()
.collect(Collectors.toSet());
System.out.println(collect);
List<Integer> collect1 = arrayList.stream()
.collect(Collectors.toList());
System.out.println(collect1);
HashSet<Integer> collect2 = arrayList.stream()
.collect(Collectors.toCollection(HashSet::new));
System.out.println(collect2);
//分组 {group=[444, 555, 666, 777, 555]}
Map<String, List<Integer>> collect3 = arrayList.stream()
.collect(Collectors.groupingBy((x) -> "group"));//将返回值相同的进行分组
System.out.println(collect3);
//多级分组 {group={777=[777], 666=[666], 555=[555, 555], 444=[444]}}
Map<String, Map<Integer, List<Integer>>> collect4 = arrayList.stream()
.collect(Collectors.groupingBy((x) -> "group", Collectors.groupingBy((x) -> x)));
System.out.println(collect4);
//分区 {false=[444], true=[555, 666, 777, 555]}
Map<Boolean, List<Integer>> collect5 = arrayList.stream()
.collect(Collectors.partitioningBy((x) -> x > 500));
System.out.println(collect5);
//汇总
DoubleSummaryStatistics collect6 = arrayList.stream()
.collect(Collectors.summarizingDouble((x) -> x));
System.out.println(collect6.getMax());
System.out.println(collect6.getCount());
//拼接 444,555,666,777,555
String collect7 = arrayList.stream()
.map(s -> s.toString())
.collect(Collectors.joining(","));
System.out.println(collect7);
//最大值
Optional<Integer> integer = arrayList.stream()
.collect(Collectors.maxBy(Integer::compare));
System.out.println(integer.get());