一、jdk1.8新特性Lambda表达式
前言:
JDK1.8是2014年发布更新的新特性有、接口的更新、lambda表达式、方法的引用、Stream API、函数式接口、Hashorn、JavaFX、DateTime,同是出现了一种新的编程思想“函数式编程思想”,在早起我们接触到Java中d的编程思想都是面向对象的编程思想,而面向对象强调的是“一切皆对象”,若果想要做什么事情,必须先构建对象,函数式编程思想则强调的是“做什么,而不是这都那么做”。
一、lambda表达式:
lambda表达式是JDK1.8中引进的一直一种编程思想,在有些情况下极大的简化了java开发中的代码编写,下面来看一下传统意义面向对象的写法和lambda表达式编写代码的不同,以下分别以Runnable接口开启一个线程为例:
public class test1 { public static void main(String[] args){ Runnable task = new Runnable() { public void run() { System.out.println("启动线程"); } }; new Thread(task).start(); } }
public class test2 { public static void main(String[] args){ new Thread(() -> System.out.println("启动线程")).start(); } }
上面test1启动一个线程这里用的是匿名内部类的实现,创建一个Runnable实例交给Thread,而test2则是使用了lambda表达式的实现方式,可以看出lambda表达式的方式使原本复杂的代码变得非常简洁,而对于lambda表达式中的()、-> 等一些特殊符号代表的意思下面主要来看一下。
1:lambda表达式的标准格式。
在JDK1.8引入了lambda后,使用lambda表达式时,它是有一些特定的格式,这其中主要包含的一下几点注意的地方:
(1)、一些参数:(如果参数有多个,如果参数没有则留空)
(2)、一个箭头:(箭头在这里是固定的写法)
(3)、箭头后面代码的具体实现:(大括号里面就是我们需要编写的具体代码)
具体来说就是:(参数类型 参数名称,…………)-> { 具体的代码实现 };来看一下一个无惨无返回值得lambda表达式的写法,
public interface Lambda { void run(); }
public class test1 { public static void main(String[] args){ //lambda表达式方式 test(() -> {System.out.println("测试lambda表达式");}); } public static void test(Lambda lambda){ lambda.run(); } }
带参且有返回值lambda表达式的写法:
public interface Lambda { int run(int a, int b); }
public class test1 { public static void main(String[] args){ //lambda表达式方式 test((int a, int b) -> { System.out.println(a + b);return a + b;}); } public static void test(Lambda lambda){ lambda.run(3, 5); } }
2:lambda表达式的省略格式。
lambda表达式在编写的过程中因为参数的不同等原因可以简写一些不需要的内容,就如上面刚开始的Runnable启动线程的lambda编写方式和测试中lambda编写方式,其中Runnable的实现中没有大括号,而这里其实是省略了大括号。
(1)、参数类型可以省略,但是只能同是省略所有参数类型,或者干脆都不省略,不能只是省略个别参数类型,如下省略int参数的类型。
public class test1 { public static void main(String[] args){ //lambda表达式方式 test(( a, b) -> { System.out.println(a + b);return a + b;}); } public static void test(Lambda lambda){ lambda.run(3, 5); } }
(2)、如果参数只有一个小括号可以省略。
public interface Lambda { int run(int a); }
public class test1 { public static void main(String[] args){ //lambda表达式方式 test( a -> {return a ;}); } public static void test(Lambda lambda){ lambda.run(3); } }
(3)、如果大括号之内的语句只有一个,那么无论是否有返回值,return、{}和分号都可以省略
public class test1 { public static void main(String[] args){ //lambda表达式方式 test( (a, b) -> a + b ); } public static void test(Lambda lambda){ lambda.run(3,5); } }
3:lambda表达式的使用前提条件:
在java中我们如果要想使用lambda表达式,lambda表达式不许要有上下文推导,简单来说就是根据我们编写的上下文推导出我们要调用的是哪个方法。
(1)、根据方法的参数推导得出lambda对应的接口,例如最开始Runnable启动一个线程的lambda表达式的方式的写法,Thread对象中需要传入一个Runnable的实现,由此我们可以把之前的代码改成如下写法:
public class test2 { public static void main(String[] args){ new Thread(() -> System.out.println("启动线程1")).start(); Runnable task = () -> System.out.println("启动线程2"); new Thread(task).start(); } }
(2)、根据局部变量的赋值来推导出lambda对应的接口,也就是上面之前我们测试的那种写法,写一个方法吧接口类型当做参数传入。
二、函数式接口的定义和使用:
在之前我们使用lambdab表达式时我们都需要定义一个接口,而我们定义的这个接口就是函数式接口,所谓的函数式接口就是支持函数式编程的接口,同时也就是支持lambda表达式的接口。
1、函数式接口的定义,有且只有一个抽象方法,但可以存在defult、static、private方法。
2、如果一个接口上面写了@functionalInterface注解,此注解数用来检测一个接口是否是函数式接口,并没有其他的意义,如果不是函数式接口编译检测时会报错。
三、lambda表达式和内部类的不同。
1、在这里强调一点,lambda表达式的写法并不是“语法糖”,他与语法糖有着本质区别,语法糖只是让代码更加简便,但底层实现原理并不会改变,列如方法中的可变参数、超级for循环等,他们的底层原理都是一个数组和迭代器。
2、所需类型不同:lambda表达式匿名内部类的实现,可以用接口、可以用抽象类也可以使用普通的类,而lambda表达式只能用接口。
3、使用限制不同:如果接口中只有一个抽象方法可以使用lambda表达式也可是使用匿名内部类,如果存在多个抽象方法则只能使用匿名内部类。
4、实现原理不同:匿名内部类就是一个类,编译后会单独的生成一个.class文件,lambda表达式编译后丙类有.class文件,对应的字节码则是在运行的时候才会生成:注:在java7中引入了invokedynamic指令,该指令的作用是允许程序运行后可以动态的生成一些字节码,在这里就不如说是lambda表达式。