学习笔记一 lambda表达式
1.要搞清楚lambda表达式,首先得清楚一个概念:函数式接口。函数式是一种包含单一抽象方法的接口,即接口中只有一个抽象方法。但接口中可以有Object已经实现的方法,像equals、toString等方法。
2.总的来说,我们可以将lambda表达式视为实现匿名内部类的主体,它可以被赋值给接口引用,可以是方法的参数,可以是方法的返回类型,且不能脱离上下文而存在。
3.lambda表达式必须匹配接口中单一抽象方法签名的参数类型和返回类型,这被称为与方法签名兼容。
4.举几个例子:
(1)被赋值给接口引用:
a.lambda表达式只包含函数参数和函数体,并且使用->隔开,省略了方法名。由于run方法没有参数,所以使用一对空括号;由于这里函数体只有一行代码,所有不需要大括号,如果有多行则必须加大括号。
b.这里要注意一下:任何表达式求值都会自动换回,且表达式的返回值必须与方法的返回值一致。在本例中,由于println方法返回的是void,所有表达式也会返回void,与run方法的返回类型相匹配。
c.在这个例子中,在编译代码时,编译器解析到传入的接口是Runnable(至于为什么可以自己查阅),从而获知单一的抽象发法run的签名(方法的签名由方法名+形参列表+返回值构成),进而了解到了该方法没有参数,也没有返回值。
d.为什么所实现方法的名称没有那么重要呢,我想应该是lambda表达式可以唯一确定接口,方法,以及方法签名,这也是为什么他不能脱离上下文存在的部分原因(个人的理解)。
e.由于lambda表达式属于接口的实现,也可以简单看成对匿名内部类的改写,所以可以将其赋值给接口类型的引用:
FilenameFilter接口也只有一个抽象方法,它的签名如下:
b.lambda表达式箭头左边的为方法参数,参数的类型可以省略,当然也可以不省略;右边的是函数体,返回布尔型与方法的返回值一致。这里的return字样必须省略,因为方法体只有一行。如果改成如下形式,即方法体有多行,则必须加上return关键字。
c.在这个例子中,在编译时,编译器发现list方法传入一个FilenameFilter类型的参数,从而获知其唯一抽象方法accept的签名,进而了解accept的参数为File和String,因此兼容的lambda表达式必须匹配这些类型(因此编译器能够解析,所以参数类型可以省略)。由于方法的返回值是布尔型,所以箭头右侧的表达式也必须返回布尔型。
d.这个例子也说明了lambda表达式不能脱离上下文而存在,只有依靠上下文,它才知道自己是一个什么类型接口的实现,才会进而获知方法与方法的签名。
(3)lambda表达式作为返回值:
对数组中的字符串元素进行从大到小的排序,这是可以利用比较器(),代码我们可以这样写:
b.从上面也可以看到,lambda表达式确实实现了代码的简化,方便书写。
c.这里注意一个问题,Comparator接口不止一个方法,还有一个equals方法,但函数式接口可以有Object类中已经实现的方法
5.总结
(1)lambda表达式虽然只有方法参数和方法体,但其实现了接口子类该有的功能,相当于一个接口子类的实例,可以被赋值给引用类型的接口,因此可以作为函数参数,也可以作为返回值(个人理解)
(2)匿名内部类能充当的角色,lambda表达式都能充当,简单来看,lambda表达式相当于对匿名内部类的改写。
(3)lambda表达式的省略规则:
a、小括号内的参数类型可以省略;
b、如果小括号内有且仅有一个参数,则小括号可以省略;
c、如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字、以及语句分号。
#笔记#
2.总的来说,我们可以将lambda表达式视为实现匿名内部类的主体,它可以被赋值给接口引用,可以是方法的参数,可以是方法的返回类型,且不能脱离上下文而存在。
3.lambda表达式必须匹配接口中单一抽象方法签名的参数类型和返回类型,这被称为与方法签名兼容。
4.举几个例子:
(1)被赋值给接口引用:
在使用匿名内部类用实现接口的方式创建一个线程,我们一般会这样写:
new Thread(new Runnable(){
public void run(){
System.out.println("hello,world");
}
}).start();
而采用lambda表达式,进行改写,是这样的: new Thread(()->System.out.println("hello,world")).start(); 从这里可以看出:a.lambda表达式只包含函数参数和函数体,并且使用->隔开,省略了方法名。由于run方法没有参数,所以使用一对空括号;由于这里函数体只有一行代码,所有不需要大括号,如果有多行则必须加大括号。
b.这里要注意一下:任何表达式求值都会自动换回,且表达式的返回值必须与方法的返回值一致。在本例中,由于println方法返回的是void,所有表达式也会返回void,与run方法的返回类型相匹配。
c.在这个例子中,在编译代码时,编译器解析到传入的接口是Runnable(至于为什么可以自己查阅),从而获知单一的抽象发法run的签名(方法的签名由方法名+形参列表+返回值构成),进而了解到了该方法没有参数,也没有返回值。
d.为什么所实现方法的名称没有那么重要呢,我想应该是lambda表达式可以唯一确定接口,方法,以及方法签名,这也是为什么他不能脱离上下文存在的部分原因(个人的理解)。
e.由于lambda表达式属于接口的实现,也可以简单看成对匿名内部类的改写,所以可以将其赋值给接口类型的引用:
Runnable r=new Thread(()->System.out.println("hello,world"));
((Thread) r).start(); //为什么向下转型相信大家都知道,是为了调用Thread的特有方法。 (2)lambda表达式作为方法的参数:FilenameFilter接口也只有一个抽象方法,它的签名如下:
boolean accept(File dir,String name)用这个接口过滤一个文件,我们一般这样写:
File directory=new File("d:\\workspace"); String[] names=directory.list(new FilenameFilter(){ // list方法返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 public boolean accept(File dir,String name){ return name.endsWith(".java"); //返回后缀名为.java的文件 }
}); System.out.println(Arrays.asList(names)); //将数组转换为集合打印输出而用lambda表达式,可以这样写:
File directory=new File("d:\\workspace"); String[] names=directory.list((dir,name)->name.endsWith(".java")); System.out.println(Arrays.asList(names));a.这里,相信大家能够看出:(dir,name)->name.endsWith(".java")就是一个lambda表达式,这里它作为list方法的参数。
b.lambda表达式箭头左边的为方法参数,参数的类型可以省略,当然也可以不省略;右边的是函数体,返回布尔型与方法的返回值一致。这里的return字样必须省略,因为方法体只有一行。如果改成如下形式,即方法体有多行,则必须加上return关键字。
File directory=new File("d:\\workspace"); String[] names=directory.list((dir,name)->{ return name.endsWith(".java"); });System.out.println(Arrays.asList(names));
c.在这个例子中,在编译时,编译器发现list方法传入一个FilenameFilter类型的参数,从而获知其唯一抽象方法accept的签名,进而了解accept的参数为File和String,因此兼容的lambda表达式必须匹配这些类型(因此编译器能够解析,所以参数类型可以省略)。由于方法的返回值是布尔型,所以箭头右侧的表达式也必须返回布尔型。
d.这个例子也说明了lambda表达式不能脱离上下文而存在,只有依靠上下文,它才知道自己是一个什么类型接口的实现,才会进而获知方法与方法的签名。
(3)lambda表达式作为返回值:
对数组中的字符串元素进行从大到小的排序,这是可以利用比较器(),代码我们可以这样写:
public class Hello { private static Comparator<String> newComparator(){ return new Comparator<String>(){ public int compare(String o1,String o2){ //决定从大到下排序的关键
return o2.length()-o1.length();
}
};
}
public static void main(String[] args){ String[] array={"abdc","cdd","fief","kdfjkd"}; System.out.println(Arrays.toString(array));
Arrays.sort(array,newComparator());
System.out.println(Arrays.toString(array));
}
}我们也可以这样写,让lambda表达式作为一个方法的返回值
public class Hello { private static Comparator<String> newComparator(){ //由于已经用泛型指定比较器是String,所以编译时能够检测到a,b的参数类型是String
return (a,b)->b.length()-a.length();
}
public static void main(String[] args){ String[] array={"abdc","cdd","fief","kdfjkd"}; System.out.println(Arrays.toString(array));
//这里调用方法,实际上就是一个Comparator的实例。
Arrays.sort(array,newComparator());
System.out.println(Arrays.toString(array));
}
}a.在这个例子中newComparator的返回值是Comparator,因此lambda表达式就可以判断出自己继承的接口,这里也说明了lambda表达式不能脱离上下文而存在。
b.从上面也可以看到,lambda表达式确实实现了代码的简化,方便书写。
c.这里注意一个问题,Comparator接口不止一个方法,还有一个equals方法,但函数式接口可以有Object类中已经实现的方法
5.总结
(1)lambda表达式虽然只有方法参数和方法体,但其实现了接口子类该有的功能,相当于一个接口子类的实例,可以被赋值给引用类型的接口,因此可以作为函数参数,也可以作为返回值(个人理解)
(2)匿名内部类能充当的角色,lambda表达式都能充当,简单来看,lambda表达式相当于对匿名内部类的改写。
(3)lambda表达式的省略规则:
a、小括号内的参数类型可以省略;
b、如果小括号内有且仅有一个参数,则小括号可以省略;
c、如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字、以及语句分号。
查看10道真题和解析
网易游戏公司福利 650人发布