java8.Lambda表达式

来源:互联网 发布:js事件对象 编辑:程序博客网 时间:2024/06/06 09:49
转载自:http://www.jb51.net/article/48304.htm
              http://www.oschina.net/translate/everything-about-java-8

Lambda表达式

       使用Java8之前的语法,如何实现比较器:
[java] view plain copy
  1. List<Integer> list = Arrays.asList(7412);  
  2. Collections.sort(list, new Comparator<Integer>() {  
  3.       @Override  
  4.       public int compare(Integer a, Integer b) {  
  5.            return a > b ? 1 : (a == b) ? 0 : -1;  
  6.       }  
  7. });  
  8. System.out.println(list);// [1, 2, 4, 7]  
       在Java 8 中就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:
[java] view plain copy
  1. Collections.sort(list, (Integer a, Integer b) -> {  
  2.       return a > b ? 1 : (a == b) ? 0 : -1;  
  3. });  
       代码变得更段且更具有可读性,但是实际上还可以写得更短:
[java] view plain copy
  1. Collections.sort(list, (Integer a, Integer b) -> a > b ? 1 : (a == b) ? 0 : -1);  
       对于函数体只有一行代码的,可以去掉大括号{}以及return关键字,但是还可以写得更短点:
[java] view plain copy
  1. Collections.sort(list, (a, b) -> a > b ? 1 : (a == b) ? 0 : -1);  
       Java编译器可以自动推导出参数类型,所以可以不用再写一次类型。
       当把经典风格java语法转变为Lambda表达式语法时,主要关注接口方法的参数和功能逻辑。

       另外一个例子,如果打算写一个方法,此方法接收一个Lambda表达式作为参数,那么该怎么写?首先把方法参数声明成函数接口,然后才能传递Lambda表达式进来,如下所示:
[java] view plain copy
  1. interface Action {  
  2.     void doThing(String param);  
  3. }  
[java] view plain copy
  1. public void func(Action actor) {  
  2.     actor.doThing("Hello World!");  
  3. }  
       如果想要调用func()方法,那么通常地做法,给func方法传递一个Action的匿名实现类。如下所示:
[java] view plain copy
  1. new LambdaTest().func(new Action() {  
  2.       @Override  
  3.       public void doThing(String param) {  
  4.            System.out.println("Hi! " + param);  
  5.       }  
  6. });  
       但是现在有函数接口做参数类型,所以可以用下面的方式调用func ():
[java] view plain copy
  1. new LambdaTest().func((String parm) -> {  
  2.       System.out.println("Hi! " + parm);  
  3. });  
       甚至可以更简单:
[java] view plain copy
  1. new LambdaTest().func(parm -> System.out.println("Hi! " + parm));  

接口的默认方法(default)

       Java 8允许给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:
[java] view plain copy
  1. public class Test {  
  2.     public static void main(String[] args) {  
  3.         Formula formula = new Formula() {  
  4.             @Override  
  5.             public double calculate(int a) {  
  6.                 return sqrt(a * 100);  
  7.             }  
  8.         };  
  9.         System.out.println(formula.calculate(100)); // 100.0  
  10.         System.out.println(formula.sqrt(16)); // 4.0  
  11.     }  
  12. }  
  13.   
  14. interface Formula {  
  15.     double calculate(int a);  
  16.   
  17.     default double sqrt(int a) {  
  18.         return Math.sqrt(a);  
  19.     }  
  20. }  

函数式接口

       Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为默认方法不算抽象方法,所以也可以给你的函数式接口添加默认方法。
       可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保接口一定达到这个要求,只需要给接口添加 @FunctionalInterface 注解,编译器如果发现标注了这个注解的接口有多于一个抽象方法的时候会报错的。
[java] view plain copy
  1. @FunctionalInterface  
  2. interface Converter<F, T> {  
  3.     T convert(F from);  
  4. }  
[java] view plain copy
  1. Converter<String, Integer> converter = (aa) -> Integer.valueOf(aa);  
  2. Integer converted = converter.convert("123");  
  3. System.out.println(converted); // 123  
需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。

       JDK8中新增了一个包,java.util.function,这个包里有一些专门给新增的API使用的函数接口。
       下面列出几个java.util.function中定义的接口:
[java] view plain copy
  1. public interface Consumer<T> : void accept(T t);//在T上执行一个操作,无返回结果  
  2. public interface Supplier<T> : T get();//无输入参数,返回T的实例  
  3. public interface Predicate<T> : boolean test(T t);// 输入参数为T的实例,返回boolean值  
  4. public interface Function<T, R> : R apply(T t);// 输入参数为T的实例,返回R的实例  


方法引用:                        

静态方法引用:      String::valueOf
非静态方法引用:  Object::toString
继承的函数引用:   x::toString
构造函数引用:     ArrayList::new

方法引用                  等价的lambda表达式
String::valueOf         x -> String.valueOf(x)
Object::toString        x -> x.toString()
x::toString                () -> x.toString()
ArrayList::new         () -> new ArrayList<>()
0 0