Java 8 新特性
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
友情链接
菜鸟教程:点我跳转Java8新特性菜鸟教程地址
JDK:点我跳转Jdk8官网下载地址
一.Lambda表达式
Lambda 是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,将代码像数据一样进行传递。使用它可以写出更简洁,更灵活的代码。作为一种更紧凑的代码风格。使Java的语言表达能力得到了提升。
语法:
(o1,o2) -> Integer.compare(o1,o2);
->
:lambda操作符,也叫箭头操作符-> 左边
:lambda形参列表 (其实就是接口中的抽象方法的形参列表)-> 右边
:lambda体(其实就是重写的抽象方法的方法体)
案例:
- 格式:无参数,无返回值
@Test public void test(){ //原写法 Runnable runnable=new Runnable() { @Override public void run() { System.out.println("无参无返回值原写法"); } }; runnable.run(); //Lambda表达式写法 Runnable lrunnable =()->{System.out.println("无参无返回值Lambda表达式写法");}; lrunnable.run(); }
- 格式:Lambda 需要一个参数,但是没有返回值
@Test public void test(){ //原写法 Consumer<String> consumer=new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("需要一个参数没有返回值,原写法"); //Lambda表达式写法 Consumer<String> lconsumer =(String s)->{System.out.println(s);}; lconsumer.accept("需要一个参数没有返回值,Lambda表达式写法"); }
- 格式:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
@Test public void test(){ //原写法 Consumer<String> consumer=new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("需要一个参数没有返回值,原写法"); //Lambda表达式写法 Consumer<String> lconsumer =(s)->{System.out.println(s);}; lconsumer.accept("需要一个参数没有返回值并且数据类型可以省略, Lambda表达式写法"); }
- 格式:Lambda 若只需要一个参数时,参数的小括号可以省略
@Test public void test(){ //原写法 Consumer<String> consumer=new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("需要一个参数没有返回值,原写法"); //Lambda表达式写法 Consumer<String> lconsumer = s ->{System.out.println(s);}; lconsumer.accept("需要一个参数没有返回值,数据类型可以省略,小括号也可以省略 Lambda表达式写法"); }
- 格式:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
@Test public void test(){ //原写法 Comparator<Integer> comparator=new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; System.out.println(comparator.compare(1,2)); //Lambda表达式写法 Comparator<Integer> lcomparator=(o1,o2)->{return o1.compareTo(o2);}; System.out.println(lcomparator.compare(1,2)); }
- 格式:当 Lambda 体只有一条语句时, return 与大括号都可以省略
@Test public void test(){ //原写法 Comparator<Integer> comparator=new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compareTo(o2); } }; System.out.println(comparator.compare(1,2)); //Lambda表达式写法 Comparator<Integer> lcomparator=(o1,o2)-> o1.compareTo(o2); System.out.println(lcomparator.compare(1,2)); }
总结:
- lambda表达式的本质:作为函数式接口的实例
-> 左边
: 如果使用泛型,lambda形参列表的参数类型可以省略(类型推断),如果lambda形参列表只有一个参数()
也可以省略。-> 右边
:lambda体使用一对{}
包裹,如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}
和return
关键字 (如果省略了return关键字{}也一定要去掉) 。
二.函数式(Funcation)接口
如果一个接口中,只声明了一个抽象方法(可以有多个非抽象方法),则此接口就称为函数式接口,函数式接口可以被隐式转换为 lambda 表达式。
学习之前先来看一下JDK 1.8 之前已有的函数式接口 Runnable
我们常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解。该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上@FunctionInterface,那么编译器会报错。
自定义函数式接口:
/** * @author mengzhichao * @create 2021-06-06-18:25 */ @FunctionalInterface public interface MyInterface { void method(); }
总结:在Java8中,Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例。那么该对象就可以用Lambda表达式来表示。所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
JDK 1.8 新增加的函数接口:
接口 | 描述 |
BiConsumer<T,U> | 代表了一个接受两个输入参数的操作,并且不返回任何结果 |
BiFunction<T,U,R> | 代表了一个接受两个输入参数的方法,并且返回一个结果 |
BinaryOperator< T > | 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
BiPredicate<T,U> | 代表了一个两个参数的boolean值方法 |
BooleanSupplier | 代表了boolean值结果的提供方 |
Consumer | 代表了接受一个输入参数并且无返回的操作 |
DoubleBinaryOperator | 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
DoubleConsumer | 代表一个接受double值参数的操作,并且不返回结果。 |
DoubleFunction< R > | 代表接受一个double值参数的方法,并且返回结果 |
DoublePredicate | 代表一个拥有double值参数的boolean值方法 |
DoubleSupplier | 代表一个double值结构的提供方 |
DoubleToIntFunction | 接受一个double类型输入,返回一个int类型结果。 |
DoubleToLongFunction | 接受一个double类型输入,返回一个long类型结果 |
DoubleUnaryOperator | 接受一个参数同为类型double,返回值类型也为double 。 |
Function<T,R> | 接受一个输入参数,返回一个结果。 |
IntBinaryOperator | 接受两个参数同为类型int,返回值类型也为int 。 |
IntFunction< R > | 接受一个int类型输入参数,返回一个结果 。 |
IntPredicate | 接受一个int输入参数,返回一个布尔值的结果。 |
IntSupplier | 无参数,返回一个int类型结果。 |
IntToDoubleFunction | 接受一个int类型输入,返回一个double类型结果 。 |
IntToLongFunction | 接受一个int类型输入,返回一个long类型结果。 |
IntUnaryOperator | 接受一个参数同为类型int,返回值类型也为int 。 |
LongBinaryOperator | 接受两个参数同为类型long,返回值类型也为long。 |
LongConsumer | 接受一个long类型的输入参数,无返回值。 |
LongFunction< R > | 接受一个long类型输入参数,返回一个结果。 |
LongPredicate | R接受一个long输入参数,返回一个布尔值类型结果。 |
LongSupplier | 无参数,返回一个结果long类型的值。 |
LongToDoubleFunction | 接受一个long类型输入,返回一个double类型结果。 |
LongToIntFunction | 接受一个long类型输入,返回一个int类型结果。 |
LongUnaryOperator | 接受一个参数同为类型long,返回值类型也为long |
ObjDoubleConsumer< T > | 接受一个object类型和一个double类型的输入参数,无返回值。 |
ObjIntConsumer< T > | 接受一个object类型和一个int类型的输入参数,无返回值。 |
Predicate< T > | 接受一个输入参数,返回一个布尔值结果。 |
Supplier< T > | 无参数,返回一个结果。 |
ToDoubleBiFunction<T,U> | 接受两个输入参数,返回一个double类型结果 |
ToDoubleFunction< T > | 接受一个输入参数,返回一个double类型结果 |
ToIntBiFunction<T,U> | 接受两个输入参数,返回一个int类型结果。 |
ToIntFunction< T > | 接受一个输入参数,返回一个int类型结果。 |
ToLongBiFunction<T,U> | 接受两个输入参数,返回一个long类型结果。 |
ToLongFunction< T > | 接受一个输入参数,返回一个long类型结果。 |
UnaryOperator< T > | 接受一个参数为类型T,返回值类型也为T。 |
案例(再此只演示极个别常用的,小伙伴们私底下可以自行练习):
- consumer即消费接口,传入一个参数,并对其进行相应的操作
public class LambdaTest { public void happyTime(double money,Consumer<Double> consumer){ consumer.accept(money); } @Test public void test(){ //原写法 happyTime(500, new Consumer<Double>() { @Override public void accept(Double aDouble) { System.out.println("原写法,价格为:"+aDouble); } }); //Lambda表达式写法 happyTime(500,money-> System.out.println("Lambda表达式写法,价格为:"+money)); } }
- supplier即供给接口,可以传入数据,作为一个容器;
public class LambdaTest { @Test public void test(){ //原写法 Supplier<String> supplier=new Supplier<String>() { @Override public String get() { return "原写法,供给型接口"; } }; System.out.println(supplier.get()); //Lambda表达式写法 Supplier<String> lSupplier=()->"lambda写法,供给型接口"; System.out.println(lSupplier.get()); } }
- function即方法接口,主要是用作数据类型之间的转换;
public class LambdaTest { @Test public void test(){ //原写法(给一个int 转成字符串并返回) Function<Integer,String> function=new Function<Integer, String>() { @Override public String apply(Integer integer) { return String.valueOf(integer); } }; System.out.println(function.apply(10).getClass().getName()); //Lambda表达式写法 Function<Integer,String> lFunction=(integer) -> String.valueOf(integer); System.out.println(lFunction.apply(20).getClass().getName()); } }
- predicate即判断接口,传入参数,而后返回判断的结果true/false;
public class LambdaTest { //根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定 public List<String> filterString(List<String> list, Predicate<String> predicate){ List<String> filterList=new ArrayList<>(); for (String s:list){ if (predicate.test(s)){ filterList.add(s); } } return filterList; } @Test public void test(){ //原写法 List<String> list=Arrays.asList(new String[]{"上海", "香港", "澳门", "曹县"}); List<String> filterString = filterString(list, new Predicate<String>() { @Override public boolean test(String s) { return "曹县".equals(s) ? true : false; } }); System.out.println(filterString); //Lambda表达式写法 List<String> lfilterString = filterString(list, s -> "上海".equals(s) ? true : false); System.out.println(lfilterString); } }