Lambda表达式
第一节 lambda表达式入门
java8才提出的一种新语法。
- 面向过程的程序语言——参数是基本类型的变量
- 面向对象语言——传递基本类型的变量、传递对象变量
- 函数式程序语言设计——传递一个方法/代码块(代码比较简洁)
1.lambda表达式本身就是一个参数,也是一个函数,可以传递给其他高阶函数。
只有一句的话,return都不要写
坚决不声明返回值的类型,没有权限的设置,单独语句不用大括号,写了return必须带大括号。
是为了保持参数的精简
第二节:函数式接口
lambda表达式与接口的关系:lambda表达式可以转化为接口对象。
Comparator<String> c = (String first, String second)-> first.length() - second.length();
lambda表达式自动填充变为接口方法的实现。
函数式接口:
- 是一个接口,符合java接口的定义
- 只包含一个抽象方法的接口
- 可以包括其他的default方法、static方法、private方法。可以增强接口的功能。
- 由于只有一个未实现的方法,所以lambda方法可以自动填上这个尚未实现的方法。
- 采用lambda表达式,可以自动创建出一个(伪)嵌套类的对象(没有实际的嵌套类class文件产生),然后使用,比真正嵌套类更加轻量,更加简洁高效。如果是上面的这个嵌套类,就会产生出一个含有$符号的文件。
自定义函数接口推荐使用FuctionalInterface
来注解,编译器就回来帮你检查。
大量的自定义的函数式接口使得源码膨胀
predicate:接收一个参数,返回boolean值(注意调用的是test方法)
Predicate<String> oddLength = s -> s.length()%2 == 0 ? false:true;
for(String p : palanets){
if(oddLength.test(p)){
System.out.println(p);
}
}
Consumer:接收一个参数,做操作,无返回
Supplier:无输入参数,返回一个数据
Function:接受一个参数,返回一个参数
第三节 方法引用
lambda表达式支持传递现有的类库函数,这就被称为方法引用。格式是::
Comparator<String> c = (String first, String second)-> first.length() - second.length();
Arrays.sort(planets, (String first, String second)->first.length()-second.length());
Arrays.sort(palnets,String::compareToIgnoreCase);
- 静态方法的引用:类名::静态方法名
- 通过实例方法引用:类名::实例方法名
- 通过对象调用其方法:对象名::方法名
- 支持this::instanceMethod调用
- 支持super::instanceMethod调用
- Class::new,调用某类构造函数,支持单个对象的构建
- Class[]::new,调用某类构造函数,支持数组对象的构建
自动填充接口的方法,这个玩意得好好理解呀。这个虽然不能算多态,但是同一个方法,同一类型的参数竟然可以运行处这么多不同的方法?
可以通过this指向自己,与其他的进行比较
super的引用:
通过new调用构造函数来调用函数
这里的new就会调用默认的person构造方法,调用s.get()
相当于调用了person的构造函数生成一个对象。
数组对象的创建:与前面的方法不一样的地方在于多了一个[]
第四节:lambda表达式的应用问题
lambda表达式应用
- 类型信息
- 重载
- 变量遮蔽
- this指代
- lambda表达式使用,以及和接口方法、嵌套类的关系
类型信息
-
类似于匿名方法,一个没有名字的方法
-
被赋值之后,可以看做是一个函数式接口的实例对象
-
大那是lambda表达式没有被存储目标类型的信息
同一个lambda表达式因为接口的不一致,其实可以产生不同的结果。
lambda表达式重载
根据类型参数自动选择合适的进行重载(这里就能判断其有没有返回值了???)
lambda表达式变量遮蔽
- lambda表达式和匿名内部类/局部内部类一样,可以捕获变量,即访问外部嵌套块的变量
- 但是变量要求是final或者是effectively final的(声明之后没有改过的变量)
- lambda表达式没有变量遮蔽的问题,因为它的内容和嵌套块有着相同的作用域。
- 在lambda表达式中,不可以声明与(外部嵌套块)局部变量同名的参数或者局部变量。
这里贴一段代码吧:
package lambda;
import java.util.function.Consumer;
public class LambdaScopeTest {
public int x = 0;
class FirstLevel{
public int x = 1;
void methodInFirstLevel(int x) {
Consumer<Integer> myConsumer = (y) ->
{
System.out.println("x = " + x);
System.out.println("y = " + y);
System.out.println("this.x = " + this.x);
System.out.println("LambdaScopeTest.this.x = " +
LambdaScopeTest.this.x);
};
myConsumer.accept(23);
}
}
public static void main(String[] args) {
LambdaScopeTest st = new LambdaScopeTest();
LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(34);
}
}
输出结果为:
x = 34
y = 23
this.x = 1
LambdaScopeTest.this.x = 0
看这段代码就可以看懂哪些变量能够访问了。
lamdba表达式的this指代
-
并不是指代的是函数式接口中的this,虽然填充的是函数式接口的方法,但是this还是指的是本身定义这个接口的那个类。
package lambda;
public class ThisScopeTest {
private String name = "def";
public static void main(String[] args) {
new ThisScopeTest().test();
}
public void test() {
StringOperation obj = ()->
{
System.out.println(this.name);
System.out.println(getName());
System.out.println(StringOperation.name);
};
obj.operate();
}
public String getName() {
return this.name;
}
}
interface StringOperation{
String name = "abc";
public void operate();
}
输出结果为:
def
def
abc
lambda表达式与默认接口、静态方法、私有方法的区别与联系。
代码很短的时候建议使用lambda表达式
- 使用系统自定义的lambda表达式引用方法
- 采用方法引用比内嵌的表达式更加清晰(建议将lambda表达式包在函数里,或者使用java内部的函数引用)