1、为什么要使用lambda表达式
lambda表达式是一段可以传递的代码,因此它可以被执行一次或多次。
在jdk8之前,向其他代码传递一段代码不是很容易,我们不能将代码块到处传递。我们需要构建一个属于某个类的对象,由它的某个方法来包含所需的代码。在其他一些语言中可以直接使用代码块。在过去的很长一段时间里,java设计者们都拒绝加入这一特性。java的优势本就在于他的简单和一致性。如果加入可以略微简化的代码,其将不易于维护。当然,还有一方面是,其他语言有大量的简单、一致、强大的API,java中的API却没有能达到这种效果。
基于以上,最近一段时间,大家不再讨论是否需要使用了,而是在讨论该怎么实现。并且很可喜的是,在jdk8中已经做了实现。
2、lambda表达式的语法
其格式为:参数、箭头->,以及一个表达式。如果相关代码无法用一个表达式表示,可以用编写方法的方式编写:既可以使用{}包裹代码并明确使用return语句。
如一个做比较的表达式可以这么写:
Comparator<String> comp = (String first, String second) -> Integer.compare(first.length(), second.length());
如果lambda表达式没有参数,可以提供一对空的小括号,如同不含参数的方法那样。
如果一个表达式的参数类型是可以被推导是,可以省略它们的类型。比如上面的String fisrt及后面的second的String参数都是可以不要的。
永远不需要为lambda表达式执行返回类型,它总是会从上下文中被推导出来。
3、函数式接口
对于只包含一个抽象方法的接口,可以通过lamba表达式来创建该接口的对象。
4、方法引用
当想要传递给其他代码的操作已经有了实现的方法,就可以使用方法引用。方法引用有三种主要的使用情况:
a、对象::实例方法
b、类::静态方法
c、类::实例方法
5、构造器引用
构造器引用同方法引用类似,不同的是在构造器引用中方法名是new。
如Button::new表示Button类的构造器引用。对于拥有多个构造器的类,选择使用哪个构造器取决于上下文。
6、变量作用域
通常,我们希望可以在lambda表达式的闭合方法或类中访问其他的变量。
一个lambda表达式包括三个部分:
a、一段代码;b、参数;c、自由变量的值,自由指的是那些不是参数并且没有在代码中定义的变量。
lambda表达式可以捕获闭合作用域中的变量值,由此需要遵守一个约束,在lambda表达式中被引用的变量的值不可以被更改。更改lambda表达式中的变量不是线程安全的。
lambda表达式的方法体与嵌套代码块有着相同的作用域。也适用于同样的命名冲突和屏蔽规则。即不允许声明一个与局部变量同名的参数或者局部变量。不能有两个同名的局部变量。在lambda中使用this关键字时,会引用创建该lambda表达式的方法的this关键字。
7、默认方法
许多开发语言都将函数表达式集成到了其集合库中。
如果一个接口中定义了一个默认方法,而另外一个父类或接口中又定义一个同名的方法,该选择哪个?java中的规则如下:
a、选择父类中的方法。如果一个父类提供了具体的实现方法,那么接口中具有相同名称和参数的默认方法会被忽略。
b、接口冲突。如果一个父接口提供了一个默认方法,而另一个接口也提供了一个具有相同名称和参数类型的方法(不管该方法是否是默认方法),那么你必须通过覆盖该方法类解决冲突。
如此设计是为了实现“类优先”的规则,并且可以和之前的设计相兼容,不会因为在新接口中添加了一个默认方法,就导致跟之前版本不兼容了。
8、接口中的静态方法
在jdk8中,可以为接口添加静态方法。从技术角度来说,这是完全合法的。只是它看起来违反了接口作为一个抽象定义的理念。
在jdk8中,很多接口已经添加了静态方法。c