前言
最近在做笔试与看一些框架的底层源码的时候,会考察和使用到Java8的某些新特性,因此感觉系统地学习下Java8的新特性是很有必要的,于是有了这篇文章。
Java8新特性
Lambda表达式
Lambda表达式是什么?
Lambda表达式其实本质是一个匿名内部类,当某个接口只定义了唯一一个抽象方法(功能单一)时,我们就可以使用(参数) - > {抽象方法的实现} 来作为这个接口的实例来使用。
为什么要使用Lambda表达式?
Lambda表达式能够使代码更加简洁。()中的参数类型可以不写;当参数只有一个时,()也可以忽略;当抽象方法的实现代码只有一行时,{}和return和;可以同时省略,注意需要同时省略。
函数式接口
什么叫函数式接口?
Java从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP)编程是一切。但是随着python、scala等语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,java不但可以支持OOP还可以支持OOF(面向函数编程)!
简单的说,在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
四大函数式接口
接口类型 | 接口介绍 |
---|---|
Consumer消费型接口 | 定义的唯一抽象方法是accept(T t) : 代表对参数类型T的变量进行操作,无返回值 |
Supplier供给型接口 | 定义的唯一抽象方法是T get() : 代表获得一个返回参数类型为T的变量 |
Function<T,R>函数型接口 | 定义的唯一抽象方法是R apply(T t) : 通过传入T类型的对象,返回一个R类型对象 |
Predicate断定型接口 | 定义的唯一抽象方法是boolean test(T t) :通过自定义的规程对传入的T类型变量进行判断,返回true Or false |
函数式接口的作用:它其实也是一种解耦的思想,当我们需要定义不同的规则时,只需要把规则传进去即可,而不需要去定义不同的方法实现,使用比较灵活。这个会在后面的Stream流中有所体现。
方法引用与构造器引用
一句话总结: 使用现成的方法代替Lambda表达式。
使用方法: ①类 :: 静态方法名 ② 实例对象 :: 实例方法名
其实Lambda表达式主要传递的是一个方法的参数和方法的实现,那只要我把现成方法传递过去,自然也能够通过获得现成方法的参数和实现来进行传递,本质是一个意思。
Stream流
Stream 流是真正地把函数式编程风格引入Java中,它的引入能够像Mysql数据库一样轻松地实现对集合数据的复杂操作,也可以利用Stream API来对数据进行并行操作。
操作步骤:
①创建一个Stream流
一般采用list.stream() 获取顺序流 或者 采用list.parallelStream() 来获取并行流。(并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。与Fork/join框架类似:将一个大的任务,进行拆分(fork)成若干个小任务(拆到足够小时),再利用线程池中的线程将一个个的小任务进行运算,再将结果进行join汇总。)
②定义Stream流的一些中间操作
对流中的数据进行过滤或者修改操作: 过滤操作filter(Predicate p) , 去重操作distinct(), 截断操作limit(int count) , (接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素)映射操作map(Function f) ,排序操作sorted(Comparator c)等
③终止操作(只有在终止操作执行时,中间操作才会执行)
一些常用的终止操作: 找出流中的最大值与最小值:max(Comparator c) 和 min(Comparator c) ; 遍历流中的每个元素foreach(Consumer c);流中是否存在某个元素anyMatch(Precidate p)等
Optional类
Optional类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
示例代码:
public interface Car {
void run();
}
public interface Caculator {
int caculate(int num1,int num2);
}
public static void main(String[] args) {
//lambada表达式测试
//testLambda1();
//testLambda2();
//四大常用函数型接口测试
//①消费型接口测试
//testConsumer();
//②供给型接口测试
//testSupplier();
//③函数型接口测试
//testFunction();
//④断定型接口测试
//testPredicate();
//Stream流测试
//testStream();
}
//无参数无返回值
private static void testLambda1(){
// 匿名内部类的写法
// Car car = new Car(){
// @Override
// public void run() {
// System.out.println("Car准备启动");
// }
// };
Car car = ()->System.out.println("Car准备启动!!!");
car.run();
}
//有参数有返回值
private static void testLambda2(){
Caculator caculator1 = (n1,n2)->n1-n2;
int result1 = caculator1.caculate(3,2);
Caculator caculator2 = (n3,n4)->n3*n4;
int result2 = caculator2.caculate(3,4);
System.out.println(result1);
System.out.println(result2);
}
//消费型接口测试
private static void testConsumer(){
function1(10,(money)->System.out.println("小汽车花了我" + money + "dollar"));
}
private static void function1(int money, Consumer<Integer> con){
con.accept(money);
}
//供给型接口测试
private static void testSupplier(){
String result = function2(()-> "I get this!");
System.out.println(result);
}
private static String function2(Supplier<String> supplier){
return supplier.get();
}
//函数型接口测试
private static void testFunction(){
String result = function3(10,(age)-> "I am "+age + " years old");
System.out.println(result);
}
private static String function3(Integer age, Function<Integer,String> function){
return function.apply(age);
}
//断定型接口测试
private static void testPredicate(){
boolean result = function4(20,(num)-> num > 10);
System.out.println(result);
}
private static boolean function4(Integer number , Predicate<Integer> predicate){
return predicate.test(number);
}
//Stream流测试
private static void testStream(){
List<Integer> list = Arrays.asList(1,5,7,9,3,4,2,22,12,15);
Stream<Integer> stream = list.stream();
//获取该列表中最大的三个数字,并把它们输出
stream.sorted((num1,num2)->num2-num1).limit(3).forEach(System.out::println);
System.out.println("-------------------------------------------------");
//将列表中大于5的数字筛选出来,将它们的值都乘2,取最大的三个
//此处结合了函数式接口,filter方法需要一个断定型接口Predicate,map方法需要一个函数型接口Functional,
// sorted方法需要一个比较型接口Comparator,forEach方法需要一个消费型接口Consumer
list.stream().filter(num -> num > 5)
.map(num1->num1*2)
.sorted((num1,num2)->num2-num1)
.limit(3)
.forEach(System.out::println);
}