前言
项目中偶有使用Java8,了解一些基本的用法,但是没有来得及系统的学习,所以一些概念比较模糊,没有理解透彻,最近把一些教程和书籍细细地看了一下,觉得豁然开朗了许多,之前有些不理解的概念也理清了,在这里总结了一下。
函数式编程(面向声明、而非过程)
在Java8中,会看到很多类似下面风格的代码:使用Labmda表达式。这种写法就是一种声明式的写法:告诉计算机要做什么,而不是怎么做。
//我们通过函数声明式的过滤出我们想要的结果。而不是在写个for循环做条件判断,然后筛选结果(过程式)
Arrays.asList(1, 3, 4, 5, 10).stream().filter(v -> v > 5).collect(Collectors.toList());
复制代码
函数接口
只有一个抽象方法,可有多个默认实现的接口。定义一个函数接口,如下:
@FunctionalInterface //添加这个注解后,编译器会检查当前的接口是否符合函数接口规范
public interface Formula {
double calucalte(int value);
default int sum(int v1, int v2) { //默认实现方法,当实现接口时可以不实现
return v1 + v2;
}
default double maxValue(Double... values) {//计算所给参数的最大值
return Arrays.stream(values).max(Double::compareTo).orElse(0.0);
}
}
复制代码
接口的默认方法
- 为什么要有这个特性
之前的接口好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类。对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。我觉得这里就解释的很好:链接
Lambda表达式
- 为什么使用Lambda表达式?
使得对接口的实现更加简单明了,代码更加清晰,对上面的代码进行测试:
//Java8以前的做法:实例化接口
Formula formu = new Formula() {
@Override
public double calucalte(int value) {
return sum(value, 10);//可以直接调用接口中的默认实现方法
}
};
System.out.println(formu.calucalte(10));
//使用Lambda表达式的做法:本质上还是接口实现。
Formula formula = a -> a + 1;//语法:参数列表->Lambda主体(相当于函数接口的实现),编译器会对参数类型进行判断
System.out.println(formula.maxValue());
复制代码
函数的传递
在Java的核心类库中,经常可以看到在方法中传递函数,下图是
Collections
类中的一个方法:
//Java8之前:
List<Integer> values = Arrays.asList(9, 1, 2, 4, 5);
Collections.sort(values, new Comparator<Integer>() {//往方法中传递函数的代码,该方法需要用到函数的执行结果
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
//Java8:一行代码解决
Collections.sort(values, Integer::compareTo);//方法引用:复用已存在的方法
复制代码
JDK提供函数接口
JDK中提供了很多实用的函数接口,大概列出了一些,具体可看下API文档,在使用过程看下源码可以理解的更透彻。
Stream API
中很多方法使用了这些函数接口。
函数接口 | 抽象方法 | 说明 |
---|---|---|
Predicate 断定型 | boolean test(T t); | 确定给定类型参数是否满足某种约束 |
Consumer 消费型 | void accept(T t); | 对给定类型参数进行操作 |
Supplier 供给型 | T get(); | 返回结果 |
R apply(T t) 函数性 | R apply(T t); | 对T类型进行操作、返回R类型结果 |
- 看下这些接口在源码当中的使用:
//Strem类中的filter方法:通过某种规则进行过滤。
Stream<T> filter(Predicate<? super T> predicate);
//使用时用Lambda表达式实现接口
List list = Stream.of(1, 3, 4, 5, 10).filter(v -> v > 5).collect(Collectors.toList());
复制代码
流(Stream)
构建流
如何从值序列、数组、文件来构建流?可用
Stream.of()
、Arrays.stream()
方法
//由值构建
String s = "sunnyDay";
List list = Stream.of(s).collect(Collectors.toList());//使用Stream.of()构建流
//由数组构建
int[] numbers = {2, 0, 2, 0};
int sum = Arrays.stream(numbers).sum();
复制代码
收集器
对
stream
中的元素作汇总:生成List、Map
Optional的使用
解决空指针缺陷问题,具体的使用可参考这篇文章
参考:《Java8实战》、《Java8函数式编程》、github.com/winterbe/ja… github.com/Snailclimb/…