java8-lambda表达式
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)