jdk1.8新特性之lambda表达式

  lambda表达式其实就是指一个匿名函数,应用最广泛的就是匿名内部类的简化。在jdk1.8之前,我们定义一个匿名内部类可能需要写一大坨代码,现在有了lambda之后,可以写的很简洁了。但不是说lambda只能用来简化匿名内部类,从lambda的实际作用和表现上来看,它就是一个变量指代了一个代码块。而能够使用lambda表达式的一个前提要求是,该变量必须实现某个函数式接口。啥是函数式接口?参考jdk1.8新特性之函数式接口。看一个匿名内部类的例子:

    FutureTask<String> coverTask = new FutureTask<String>(new Callable()
    {
        public String call()
        {
            return PortalBookCoverCacheService.getInstance().getBookCover(bookItem,
                PropertiesConfig.getProperty("cdnUrl"));
        }
    });

  上面在实例化FutureTask对象的时候,使用了Callable接口实例的匿名内部类,实际上FutureTask构造器里就是一个Callable的实例:

Callable callable = new Callable()
    {
        public String call()
        {
            return PortalBookCoverCacheService.getInstance().getBookCover(bookItem,
                PropertiesConfig.getProperty("cdnUrl"));
        }
    };

  如果我们使用lambda表达式,上面的callable变量实际上就是

    Callable callable = () ->
        {
            return PortalBookCoverCacheService.getInstance().getBookCover(bookItem,
                PropertiesConfig.getProperty("cdnUrl"));
        }
    ;

  callable变量指代的就是一段代码块,把这个变量放入FutureTask的构造器里,匿名内部类可以简化为:

                    FutureTask<String> coverTask = new FutureTask<String>(() -> {
                        return PortalBookCoverCacheService.getInstance()
                            .getBookCover(bookItem, PropertiesConfig.getProperty("cdnUrl"));
                    });

  为啥能这么简化呢?因为它符合lambda表达式规范,即Callable是一个函数式接口:

/** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */
/*
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
/*
 *
 *
 *
 *
 *
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

package java.util.concurrent;

/**
 * A task that returns a result and may throw an exception.
 * Implementors define a single method with no arguments called
 * {@code call}.
 *
 * <p>The {@code Callable} interface is similar to {@link
 * java.lang.Runnable}, in that both are designed for classes whose
 * instances are potentially executed by another thread.  A
 * {@code Runnable}, however, does not return a result and cannot
 * throw a checked exception.
 *
 * <p>The {@link Executors} class contains utility methods to
 * convert from other common forms to {@code Callable} classes.
 *
 * @see Executor
 * @since 1.5
 * @author Doug Lea
 * @param <V> the result type of method {@code call}
 */
@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

  所以可以我们通过lambda表达式省略了接口类型、方法名和方法参数(因为这里call方法根本就不需要参数),->符号的左边是参数列表(如果有参数的话),右边是方法体。lambda其实是通过编译器的强大而赋予的能力,编译器通过自动匹配接口类型、智能识别参数列表,可以像考古学家根据蛛丝马迹恢复物品的原貌的一样,还原出匿名内部类的本来面目。