lambda优于匿名类的主要优点是它更简洁。Java提供了一种生成函数对象的方法,比lambda还要简洁,那就是:方法引用( method references)。下面是一段程序代码片段,它维护一个从任意键到整数值的映射。如果将该值解释为键的实例个数,则该程序是一个多重集合的实现。该代码的功能是,根据键找到整数值,然后在此基础上加1:

    1. map.merge(key, 1, (count, incr) -> count + incr);

    请注意,此代码使用merge方法,该方法已添加到Java 8中的Map接口中。如果没有给定键的映射,则该方法只是插入给定值; 如果映射已经存在,则合并给定函数应用于当前值和给定值,并用结果覆盖当前值。 此代码表示merge方法的典型用例。
    代码很好读,但仍然有一些样板的味道。 参数count和incr不会增加太多价值,并且占用相当大的空间。 真的,所有的lambda都告诉你函数返回两个参数的和。 从Java 8开始,Integer类(和所有其他包装数字基本类型)提供了一个静态方法总和,和它完全相同。 我们可以简单地传递一个对这个方法的引用,并以较少的视觉混乱得到相同的结果:

    1. map.merge(key, 1, Integer::sum);

    方法的参数越多,你可以通过方法引用消除更多的样板。 然而,在一些lambda中,选择的参数名称提供了有用的文档,使得lambda比方法引用更具可读性和可维护性,即使lambda看起来更长。
    对于一个方法引用,你无能为力,因为你不能对lambda执行任何操作(只有一个难懂的异常 - 如果你好奇的话,参见JLS,9.9-2)。 也就是说,方法引用通常会导致更短,更清晰的代码。 如果lambda变得太长或太复杂,它们也会给你一个结果:你可以从lambda中提取代码到一个新的方法中,并用对该方法的引用代替lambda。 你可以给这个方法一个好名字,并把它文档记录下来。
    如果你使用IDE编程,它将提供替换lambda的方法,并在任何地方使用方法引用。通常情况下,你应该接受这个提议。偶尔,lambda会比方法引用更简洁。这种情况经常发生在方法与lambda相同的类中。例如,考虑这段代码,它被假定出现在一个名为GoshThisClassNameIsHumongous的类中:

    1. service.execute(GoshThisClassNameIsHumongous::action);

    这个lambda类似于等价于下面的代码:

    1. service.execute(() -> action());

    使用方法引用的代码段既不比使用lambda的代码片段更短也不清晰,所以更喜欢后者。 在类似的代码行中,Function接口提供了一个通用的静态工厂方法来返回标识函数Function.identity()。 它通常更短,更清洁,而不使用这种方法,而是使用等效的lambda内联代码:x - > x
    方法引用有五中,两种是实例方法的引用。两个实例方法中,一个是有限制的,一个是无限制的。具体的类型如下,表中1是静态方法引用,2是有限制的实例方法引用,就是使用参数中生成的对象来引用对象,3是无限制对象引用,4为构造器方法引用,5是数组方法引用,如果有疑问直接看代码。
    第二种和第三种的区别:第二种的then是lambda表达式外部的变量,而第三种str是lambda表达式的参数。

    方法引用类型 举例 等同的Lambda
    Static Integer::parseInt str -> Integer.parseInt(str)
    Bound Instant.now()::isAfter Instant then = Instant.now(); t -> then.isAfter(t)
    Unbound String::toLowerCase str -> str.toLowerCase()
    Class Constructor TreeMap::new () -> new TreeMap
    Array Constructor int[]::new len -> new int[len]
    1. package item43;
    2. /**
    3. * @author: qujundong
    4. * @date: 2020/12/8 下午10:12
    5. * @description:
    6. */
    7. import java.text.SimpleDateFormat;
    8. import java.util.Date;
    9. import java.util.function.Function;
    10. public class MethodReference {
    11. public static void main(String[] args) {
    12. //lambda
    13. strToIntFunc("1", str -> Integer.parseInt(str));
    14. //静态方法引用,静态方法和函数接口Function参数和返回值要一致
    15. strToIntFunc("1", Integer::parseInt);
    16. //lambda
    17. dateFormat(new Date(), str -> new SimpleDateFormat("yyyyMMdd").format(str));
    18. //实例方法引用,这种用法和静态方法引用类似,区别只是方法是实例还是静态
    19. dateFormat(new Date(), new SimpleDateFormat("yyyyMMdd")::format);
    20. //lambda
    21. changeStrFormat("ABC", str -> str.toLowerCase());
    22. //无限制的实例方法引用,注意这里,toLowerCase是实例方法,但具体的对象是作为参数传进来的
    23. changeStrFormat("ABC", String::toLowerCase);
    24. //lambda
    25. newIntArray(4, len -> new int[4]);
    26. //构造器方法引用,根据传入的参数,构造数组返回
    27. newIntArray(4, int[]::new);
    28. //lambda
    29. strToIntFunc("1", str -> new Integer(str));
    30. //构造器方法引用
    31. strToIntFunc("1", Integer::new);
    32. }
    33. public static int[] newIntArray(int len, Function<Integer, int[]> func) {
    34. return func.apply(len);
    35. }
    36. public static String changeStrFormat(String str, Function<String, String> func) {
    37. return func.apply(str);
    38. }
    39. public static String dateFormat(Date date, Function<Date, String> func) {
    40. return func.apply(date);
    41. }
    42. public static Integer strToIntFunc(String str, Function<String, Integer> func) {
    43. return func.apply(str);
    44. }
    45. }


    总结:如果方法引用比Lambda表达式更加简洁,那么就用方法引用,如果Lambda表达是简洁,那就用Lambda表达式。