初识lambda表达式
public class Lambda {
// () -> {}
public static void main(String[] args){
String[] strings = new String[3];
strings[0] = "bc";
strings[1] = "a";
strings[2] = "def";
for(String str : strings){
System.out.println(str);
}
// sort函数的第二个参数需要一个实现了comparator接口的类的对象
Arrays.sort(strings, new LengthComparator());
for(String str : strings){
System.out.println(str);
}
// 下方lambda表达式中的参数列表(String first, String second)的类型名String,
// 若能从上下文推断出来则不需指定
// 若参数只有一个,且类型可以由上下文推断出来,则小括号也可以省略
// 若没有参数,小括号不能省略
// 这是expression lambda,不需要写return,直接将该表达式的结果返回
Arrays.sort(strings, (String first, String second) -> Integer.compare(second.length(), first.length()));
for (String str : strings) {
System.out.println(str);
}
// 若需要写多行则用{}将后面的表达式括起来
// 这是statement lambda,return要显示的写出来
Arrays.sort(strings, (String first, String second) -> {
if (first.length() > second.length()) {
return 1;
} else if (first.length() == second.length()) {
return 0;
} else {
return -1;
}
});
for (String str : strings) {
System.out.println(str);
}
}
}
class LengthComparator implements Comparator<String>{
public int compare(String first, String second) {
return Integer.compare(first.length(), second.length());
}
}
Functional Interface
如果一个借口仅有一个抽象方法,就称为函数式接口,比如Runnable,Comparator,在任何需要Functional Interface的地方,都可以用lambda表达式
上面代码中,
Arrays.sort(strings, (String first, String second) -> Integer.compare(second.length(), first.length()));
这里,sort()的第二个参数应该是一个Comparator的对象,而Comparator是一个Functional Interface,因此可以直接传入lambda表达式,在调用该对象的compare(),就是执行该lambda表达式的语句体
如果lambda表达式的语句体会抛出异常,则对应的Functional Interface的抽象方法必须抛出该异常,否则就需要在lambda表达式中显示的捕获该异常
Runnable r = () -> {
System.out.println("--");
try{
Thread.sleep();
} catch (InterruptedException e) {}
};
如上代码中要捕获异常是因为Runnable接口的唯一的方法run方法没有抛出该异常
Method Reference
以下两种表达方式等价
(x) -> System.out.println(x)
System.out::println
其中第二行就是Method Reference
Method Reference由三种形式
1. object::instanceMethod
System.out::println
(x) -> System.out.println(x)
- Class::staticMethod
Math::pow
(x, y) -> Math.pow(x, y)
- Class::instanceMethod
String::compareToIgnoreCase
(s1, s2) -> s1.compareToIgnoreCase(s2)
其中,第三种方式会将第一个参数作为对象,调用方法,将其他的参数作为方法的参数使用
变量作用域
如下代码
public class Lambda{
public static void main(String[] args){
repeatMessage("Hello", 5);
}
public static void repeatMessage(String text, int count) {
Runnable r = () -> {
for(int i = 0;i<count;i++){
System.out.println(text);
Thread.yield();
}
};
new Thread(r).start();
}
}
注意看lambda表达式中的变量count和text,它们并没有在lambda 表达式中被定义,而是repeatMessage方法中的变量。而在yield之后,repeatMessage返回了,此时参数变量已经消失了,那么lambda如何保留text和count的呢?
我们可以说,lambda捕获了text和count两个值,在lambda表达式中,不能修改捕获的值。
比如,在lambda中加入一句
count--;
会报错!
另外,lambda表达式中不允许声明一个和局部变量同名的参数或者局部变量
在lambda中使用this时,this是它所在方法的类的对象
参考:
https://my.oschina.net/fhd/blog/419892
http://www.jb51.net/article/81204.htm