lamda 是Java8中增加的一个新特性。lamda表达式语法很简单,使用-> 将参数列表和表达式体分割开来。
(Type1 param1, Type2 param2, ..., TypeN paramN) -> { //do somthing}
(int x,int y)-> x+y 等价于 (int x,int y)->{x+y;}
如果有一个列表[1,2,3,4,5,6] 需要遍历并打印出来,如果不是用lamda表达式实现方式如下:
List<Integer> list=Arrays.asList(1,2,3,4,5,6); list.forEach(new Consumer<Integer>() { @Override public void accept(Integer t) { System.out.println(t); } });
而使用lamda表达式的写法则如下:
List<Integer> list=Arrays.asList(1,2,3,4,5,6); list.forEach(i->System.out.print(i));
当lambda表达式只是调用现有类中的具名方法时,编写lambda表达式更好的方式是使用已有的名字。
List<Integer> list=Arrays.asList(1,2,3,4,5,6); list.forEach(System.out::println);
通过上面的描述我们对Lambda有了一个大概的印象。Lambda可以简单的理解为一个匿名函数,虽然没有名字但是具有参数列表,方法体,返回类型以及抛出异常列表。
Arrays.asList(1,2,3,4,5,6).forEach(System.out::println);
这段代码是如何确定类型的呢? 首先可以推断出列表中的类型为Integer,forEach接收的表达式参数类型就是 Integer。
静态方法 refType::staticMethod (args)->refType.staticMethod(args);
绑定实例 expr::instMethod
未绑定实例 RefType::instMethod
构造器 ClsName::new
list.forEach(Integer::new); list.forEach(String::valueOf);
通过上面的示例可以看到lamda可以和匿名内部类进行转换,当然不是所有内部类都可以替换为lamda表达式的,lamda表达式必须实现一个函数式接口(java.util.function);但是二者还是有很多显著却别的。
- 内部类会创建一个拥有唯一标示的新对象,而lamda表达式可能没有,也可能有,这取决于具体实现。
- 内部类的声明会创建一个新的命名作用域,在这个作用域中,this,super指的是内部类本身的当前实例;而lamda 表达式不会引入任何新的命名作用域。
public class Hello { Runnable r1=()->{System.out.println(this);}; Runnable r2=new Runnable() { @Override public void run() { System.out.println(this); } }; public static void main(String ...args){ new Hello().r1.run(); new Hello().r2.run(); } }
结果是:
com.david.demo.lamda.core.Hello@4eec7777 com.david.demo.lamda.core.Hello$1@3b07d329
java.util.function中提供的基本函数式接口有:
void Consumer<T> (T t) ; 如:s->System.out.println(s);
boolean Predicate<T>(T t); 如: s->s.isEmpty();
T Supplier<T>(); 如: ()->new String();
U Function<T,U>(T t); 如: s->new Integer(s);