Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
注意:Lambda表达式适用于只有一个抽象方法的接口!!
自定义接口
1 2 3 | interface Fu{ void add(); } |
使用匿名内部类实现接口
1 2 3 4 5 6 7 | Fu fu = new Fu() { @Override public void add() { System.out.println( "我是add方法" ); } }; fu.add(); |
使用Lambda表达式实现接口
1 2 3 4 | Fu fu1 = ()->{ System.out.println( "我是add1方法" ); }; fu1.add(); |
接口
1 2 3 | interface F{ void add(); } |
测试
1 2 3 4 5 | //无参无返回值 F f = ()->{ System.out.println( "我是add方法" ); }; f.add(); |
接口
1 2 3 | interface F{ void add( int a); } |
测试
1 2 3 4 | F f = ( int a)->{ System.out.println( "a=" +a); }; f.add( 12 ); |
接口
1 2 3 | interface F{ int add(); } |
测试
1 2 3 4 5 | F f = ()->{ return 12 ; }; int i = f.add(); System.out.println(i); |
接口
1 2 3 | interface F{ int add( int a); } |
测试
1 2 3 4 5 | F f = ( int a)->{ return 12 +a; }; int i = f.add( 12 ); System.out.println(i); |
- Lambda表达式中 () 的参数类型可以省略 (int a,int b)==>(a,b)
- 接口中如果只有一个参数,Lambda表达式中 () 可以省略 (int a)==> (a)==>a
- 如果方法体中只有一条执行语句时 外层的 {} 可以省略
- 如果方法体中只有一条返回语句,{}和return 都可以省略
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,可以有其他普通方法,用@FunctionalInterface检验是否是函数式接口。
1 2 3 4 5 6 7 8 9 10 11 12 | @FunctionalInterface interface F1{ void t1(); default void t2(){ //不计 } static void t3(){ //不计 } public boolean equals(Object object); //不计 } |
作用:在Java中主要用在Lambda表达式和方法引用。
- Consumer<T>:消费型接口(void accept(T t))。有参数,无返回值
- Supplier<T>:供给型接口(T get())。有参数,无返回值
- Function<T,R>:函数型接口(R apply(T t))。一个输入参数,一个输出参数,两种类型可以一致,也可以不一致
- Predicate<T>:断言型接口(boolean test(T t))。输入一个参数,输出一个boolean类型的返回值
消费型接口
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 | //函数式接口的使用场景 public class Test03 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); Collections.addAll(list, 1 , 2 , 3 , 6 , 5 , 4 , 8 , 9 ); //匿名内部类 Consumer<Integer> con = new Consumer<Integer>() { @Override public void accept(Integer integer) { //参数代表集合中的每一个数据 System.out.print(integer+ " " ); } }; list.forEach( con ); System.out.println(); System.out.println( "==================" ); //Lambda表达式1 Consumer cons = (y)->{ System.out.print(y+ " " ); }; list.forEach( cons ); System.out.println(); System.out.println( "==================" ); //Lambda表达式2 list.forEach( y-> System.out.print(y+ " " ) ); } } |
断言型接口
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 | public class Test04 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); Collections.addAll(list, 1 , 2 , 3 , 6 , 5 , 4 , 8 , 9 ); //匿名内部类 Predicate<Integer> predicate = new Predicate<Integer>() { @Override public boolean test(Integer integer) { //参数o代表集合中的每一个数 if (integer<= 6 ){ return true ; //删除该数据 } return false ; //不删除该数据 } }; list.removeIf(predicate); list.forEach( x-> System.out.println(x) ); System.out.println( "=================" ); //Lambda表达式 list.removeIf( y->{ if (y<= 6 ){ return true ; } return false ; } ); list.removeIf(predicate); list.forEach( x-> System.out.println(x) ); System.out.println( "=================" ); } } |
方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。方法引用使用一对冒号 :: 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //方法引用 public class Test05 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); Collections.addAll(list, 4 , 8 , 9 ); //使用Lambda表达式 list.forEach( x-> System.out.println(x) ); System.out.println( "==================" ); //方法引用 //使用场景,参数传递过来不做任何处理,直接输出的就可以使用方法引用 list.forEach(System.out::println); } } |
构造器引用:它的语法是Class::new,或者更一般的Class< T >::new
1 | final Car car = Car.create( Car:: new ); final List< Car > cars = Arrays.asList( car ); |
静态方法引用:它的语法是Class::static_method
1 | cars.forEach( Car::collide ); |
特定类的任意对象的方法引用:它的语法是Class::method
1 | cars.forEach( Car::repair ); |
特定对象的方法引用:它的语法是instance::method
1 | final Car police = Car.create( Car:: new ); cars.forEach( police::follow ); |
Stream(流)是一个来自数据源的元素队列并支持聚合操作
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- 创建Stream:从一个数据源(集合、数组)中获取
- 中间操作:一个操作的中间链,对数据源的数据进行处理
- 终止操作:一个终止操作,执行中间操作链,并产生结果
排序去重
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //Stream 流式编程 public class StreamTest01 { public static void main(String[] args) { //需求:有一堆数据,且有重复值,要求有序去除重复值 List<Integer> list = new ArrayList<>(); Collections.addAll(list, 56 , 89 , 75 , 64 , 24 , 25 , 24 , 89 , 56 , 75 ); //流式编程处理 //获取stream Stream<Integer> stream = list.stream(); //中间操作 stream = stream.distinct() //去重操作 .sorted(); //排序 //终止操作 stream.forEach( x->{ //输出集合中元素 System.out.println(x); } ); } } |
中间操作
1 2 3 4 5 6 7 8 9 10 11 | stream = stream.distinct() //去重操作 .sorted(); //排序 .limit( 4 ); //取前四个元素 .skip( 2 ); //跳过前几个元素 .map( x->x+ 4 ); //每一个元素加上特定的值 .filter( x->{ //过滤操作,true正常返回,false不返回 if (x>= 25 ){ return true ; } return false ; } ); |
串行流
1 | Stream<Integer> stream = list.stream(); //串行流 |
并行流
1 | Stream<Integer> stream1 = list.parallelStream(); //并行流 |
Optional 类的方法
以上就是Java8新特性-Lambda表达式详解的详细内容,更多关于Java Lambda表达式的资料请关注脚本之家其它相关文章!