• 【从零单排】浅析Java 8新特性Lambda Expression


    什么是Lambda Expression

    对于Lambda Expression,我的理解是,它是一个函数表达式,如下:

    (int x, int y) -> x - y

    符号左边定义了函数的输入,右边定义了输出。在上面的例子中,我们定义了一个关于x,y的函数,这个函数的作用是计算两者之差。那么它的类型是什么呢?比如1+1这个表达式它的(返回值)类型是int。对于函数表达式,它的类型一般是由上下文定的。

    把上面的例子放到具体使用环境中,如下所示,我们可以根据上下文语义判断,该Lambda Expression的(返回值)类型是Comparator。

    Arrays.sort(input[], (int x, int y) -> x - y );

    为什么要引入Lambda Expression

    Lambda Expression是Java 8引入的一个非常重要的新特性,它也是Java第一次尝试引入函数式编程的相关内容。

    关于函数式编程,我想类比javascript,在js中函数也可以作为变量的基本类型之一,并且可以当做值一样进行传递。但是在Java中,函数是绑定在对象上的,如果需要调用一个函数foo(),需要先实例化一个对象Obj,然后再调用这个对象里的该函数Obj.foo()。如果Java中可以像js一样,直接传递函数,岂不是很酷?

    为了实现这个功能,用到了:
    - Functional Interface 函数式编程的概念
    - Java8新增的接口 Function
    - Java8新增的语法 Lambda Expression

    具体怎么实现呢?本质上来说是,新创建一个对象,然后实现Function接口。这个对象即可以看成是一个函数。

    除此之外,Lambda Expression还可以快速地创建匿名对象并实现接口方法。

    下面,对这两种模式具体讲解。

    Lambda Expression的使用 - 创建对象

    在面向接口的编程中,我们会遇到许多函数式接口(Functional Interface),即只包含一个抽象方法的接口,比如java.lang.Runnable和java.util.Comparator都是典型的函数式接口。在实际使用过程中,我们需要新建一个对象,然后implements这个接口,再实现该接口的抽象方法。如下所示:

    // 常规方法
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            log(e.getActionCommand());
        }
    });

    这段代码实现的功能是给这个button加一个ActionListener,然后在这个button有操作的时候,log该操作的名称。这样写起来有点复杂,实际上我们真正关心的只是那一行log的代码而已。如果使用Lambda Expression,可以大大简化代码量,如下所示:

    // Lambda Expression方法
    button.addActionListener(e -> log(e.getActionCommand()));

    下面,再给出一个经典的Comparator的例子参考。

    // 常规方法
    Arrays.sort(input[], new Comparator<Integer>() {
        @Override
        public int compare(int a, int b) {
            return (a-b); // in ascending order
        }
    });
    
    // Lambda Expression方法
    Arrays.sort(input[], (int a, int b) -> a-b ); 

    下面,再给出一个常用的Runnable的例子参考。

    Thread thread = new Thread(() -> {
        System.out.println("Hello " + Thread.currentThread().getName());
    });
    thread.start();

    Lambda Expression的使用 - 传递函数

    前面已经提到过了,Java不能传递函数,只能传递对象。为了实现传递函数的功能,设计上采取了一个折中的方法,创建了一个Function的接口。这样一来需要被传递的函数就可以作为一个新的对象,实现这个Function接口,来进行传递。如下示例:

    在该例中,(String v) -> v.length()这个Lambda表达式就是传递的方法(函数)。

    public class CollectionUtils {
      // 对传入的参数input进行processor操作,依旧以list的形式返回
      public static List map(List input, Function processor) {
        ArrayList result = new ArrayList();
        for (T obj : input) {
          result.add(processor.apply(obj));
      }
      return result;
    }
    
    public static void main(String[] args) {
      List input = Arrays.asList(new String[] {"apple", "orange", "pear"});
      // 统计字符串的长度
      List lengths = CollectionUtils.map(input, (String v) -> v.length());
      // 将字符串转换为大写
      List uppercases = CollectionUtils.map(input, (String v) -> v.toUpperCase());
    }

    下面,再给出一个Callable的例子。例中,delayFeedback("task", 1)就是传递的方法(函数)。

    Callable<String> delayFeedback(String feedback, long sleepSeconds) {
        return () -> {
            TimeUnit.SECONDS.sleep(sleepSeconds);
            return feedback;
        };
    }
    
    ExecutorService executor = Executors.newWorkStealingPool();
    
    List<Callable<String>> tasks = Arrays.asList(
        delayFeedback("task1", 1),
        delayFeedback("task2", 2),
        delayFeedback("task3", 3));
    
    String result = executor.invokeAny(tasks);

    反思与总结

    从上面的例子中,我们大概对Lambda Expression是什么,怎么使用有了一个大概的了解。

    回到最初的问题,再次反思Lambda Expression到底是个什么东西。我觉得,首先,可以把它看作一个Anonymous Class。其次,这个Class一定继承了某个Function Interface。至于这Class是什么类型的,需要根据上下文判断。

    那么,什么地方可以用Lambda Expression?答案是FunctionalInterface什么是FunctionalInterface?官方的回答是:

    Conceptually, a functional interface has exactly one abstract method.

    举几个常见的FunctionalInterface的例子:

    @FunctionalInterface
    public interface Comparator<T>
    
    @FunctionalInterface
    public interface Function<T,R>
    
    @FunctionalInterface
    public interface Predicate<T>
    
    public Interface ActionListener

    这正好对应了文中之前出现的例子。(说明:对于第1,2,3个,Java 8 API已经用Annotation标明了它是FunctionalInterface,对于第4个,虽然没有标,但是它符合FunctionalInterface的定义,所以也是。)

    链接

  • 相关阅读:
    JS实现类似网页的测试考卷
    Following Orders(poj1270)
    1007
    Intervals(poj1201)
    LightOJ
    1002
    King's Order(hdu5642)
    Beautiful Walls
    A. Watchmen(Codeforces 650A)
    Shortest Path(hdu5636)
  • 原文地址:https://www.cnblogs.com/maxstack/p/7550153.html
Copyright © 2020-2023  润新知