Lambda表达式详解

Lambda表达式简介

Lambda表达式是JDK8引入的一种新特性,可以用来简化代码,使代码看上去更加优雅。

Lambda表达式格式

在Java中,我们想要将String数组按照字符串长度排序,常常需要这样做:

String[] plants = new String[]{"Mercury", "Venus", "Earth", "Mars", "Jupiter",
              "Saturn", "Uranus", "Neptune"};
      Arrays.sort(plants, new Comparator<String>() {
          @Override
          public int compare(String param1, String param2) {
              return param1.length() - param2.length();
          }
      });

但是如果使用lambda表达式,可以简写成:

Arrays.sort(plants, (param1, param2) -> param1.length() - param2.length());

Lambda表达式由3个部分组成:参数、箭头、表达式。具体格式为(param) -> {表达式}

  • 参数为空可以省略为() -> {表达式}比如() -> {for (int i = 100; i >= 0;i-- ) System.out.println(i)};
  • 参数不为空,但是可以推到出类型时,可以省略类型。比如上面的代码原式为(String param1, String param2) -> {return param1.length() - param2.length()}也可以简写为
(String param1, String param2) -> {
      return param1.length() - param2.length();
}

如果只有一个参数,也可以省略小括号。

ActionListener listener = event -> System.out.println("The time is " + new Date()");
  • 方法体只有一条语句,可以省略{}和return语句。
    (String param1, String param2) -> param1.length() - param2.length();
    上述几个条件一综合,就变成了我们最终看到的样子。

什么时候可以使用Lambda表达式

对于只有一个抽象方法的接口,需要使用这种接口的对象时,就可以提供一个lambda表达式。这种接口称为函数式接口(functional interface)。
java API中提供了许多非常通用的函数式接口。比如BiFunction<T, U, R>接口。我们可以把Comparator接口替换

BiFunction<String,String, Integer> biFunction = (param1, param2) -> param1.length()+param2.length();

不过我们会发现并没有能够接收BiFunction类型的方法。这是因为类似Comparator的接口往往有一个特定的用途,而不是只提供一个有指定参数和返回类型的方法。在ArrayList中有个removeIf方法,它的接收值就是Predicate类型,就是用来传递lambda表达式的。

public interface Predicate<T> {
      boolean test(T t);
    // Additional default and static methods

方法引用

有时,已经有方法可以完成你需要的操作了,可以在lambda表达式中直接指向你的方法:
Timer t = new Timer(1000, event -> System.out.println(event)):可以简化成Timer t = new Timer(1000, Systei.out::println) ;。表达式System.out::println是一个方法引用( method reference ), 它等价于lambda 表达式x 一> System.out.println(x)。更加简便的例子是如果你想对字符串进行不考虑大小写排序,Arrays.sort(strings, String::conpareToIgnoreCase)

方法引用有3种
• object::instanceMethod
• Class::staticMethod
• Class::instanceMethod
静态方法属于类名,普通方法属于对象。
构造器方法使用有点不同,构造器方法名称可以用new代替。比如Person::new

扩展

我们查看Runnable接口时,可以发现有这样一个注解@FunctionalInterface:

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

如果你自己设计一个接口,其中只有一个抽象方法时,就可以使用@FunctionalInterface标记。这样做有2个好处。如果你无意中增加了另一个抽象方法,编译期会产生一个错误。java doc中会指出你的接口是一个函数式接口。

posted @ 2020-12-27 13:13  大龄码农一事无成  阅读(145)  评论(0)    收藏  举报