lambda表达式其本质是一个匿名函数,它没有名称,语法规则如下:
(参数)->{表达式或函数语句};
其中,参数可以为空,同时,浅显的参数类型也无需写出来,javac回通过上下文(context)自动推断出参数类型.如果参数只有一个可省去括号.
->用于分离参数和函数体(body).
右侧可以是个表达式,此时不需要花括号;也可以是函数语句,我们可以在lambda表达体中使用break,continue,return. 我们甚至可以从lambda表达体中抛出异常.但lambda不能像一个方法一样使用throws子句.
需要注意的是,
lambda表达式隐含了return关键字,所以在单个的表达式中,我们无需显式的写return关键字,但是当表达式是一个语句集合的时候,则需要显式添加return,并用花括号
{ }
将多个表达式包围起来
示例:
x->x+1
(int x, int y) -> x+y
(String msg) -> {sout(msg);}
()->{sout("helloworld");}
示例二:
String[] str = {"aa","bb","dd","cc"};
List<String> lists = new ArrayList<>(Arrays.asList(str));
lists.forEach( m -> sout(m) )
示例三:
Runnable con = new Runnable() {
@Override
public void run() {
System.out.println("helloworld1");
}
};
con.run();
等价于:
Runnable con2 = ()-> System.out.println("hello world2");
con2.run();
示例四:
//返回给定字符串的长度,隐含return语句
(String s) -> s.length()
// 始终返回42的无参方法
() -> 42
// 包含多行表达式,则用花括号括起来
(int x, int y) -> {
int z = x * y;
return x + z;
}
(**foreach的lambda函数的返回值是void**)
需要注意:
1. lambda可进行类型推断;
2. lambda表达式中不只可用主体函数,也可以使用局部变量,例子如下:
int weight = 100;
List<Apple> filterApples = filterApplesByAppleFilter(apples,
apple -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= weight);
该例子中我们在lambda中使用了局部变量weight,不过在lambda中使用局部变量必须要求该变量
显式声明为final或事实上的final ,这主要是因为局部变量存储在栈上,lambda表达式则在另一个线程中运行,当该线程视图访问该局部变量的时候,该变量存在被更改或回收的可能性,所以用final修饰之后就不会存在线程安全的问题。
3. 方法引用(::)
采用方法引用可以更近一步的简化代码,有时候这种简化让代码看上去更加的直观,先看一个例子:
/* ... 省略apples的初始化操作 */
// 采用lambda表达式
apples.sort((Apple a, Apple b) -> Float.compare(a.getWeight(), b.getWeight()));
// 采用方法引用
apples.sort(Comparator.comparing(Apple::getWeight));
方法引用通过
::
将方法隶属和方法自身连接起来,主要分为三类:
静态方法
(args) -> ClassName.staticMethod(args)
转换成
ClassName::staticMethod
参数的实例方法
(args) -> args.instanceMethod()
转换成
ClassName::instanceMethod // ClassName是args的类型
外部的实例方法
(args) -> ext.instanceMethod(args)
转换成
ext::instanceMethod(args)