Java8 Lambda本质论

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Java8 Lambda本质论脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

Lambda的本质

需求1. 按照产品的重量进行升序排序

此处使用「匿名内部类」的设计,但掺杂了较多的语法噪声,引入了不必要的复杂度。

Collections.sort(repo, new Comparator<Product>() {   @Override   public int compare(Product p1, Product p2) {     return p1.getWeight().compareTo(p2.getWeight());   } });

使用Lambda表达式,可以进一步消除语法噪声,简化设计。

Collections.sort(repo, (Product p1, Product p2) ->   p1.getWeight().compareTo(p2.getWeight()));

也就是说,Lambda其本质是「匿名内部类」的一种「语法糖」表示,存在如下3个方面的特征:

  • Anonymous Function:匿名的函数

  • Passed Around:可作为参数或返回值进行传递,甚至可以自由地存储在变量中

  • Concise:相对于匿名内部类的样板代码(Boilerplate),Lambda更加简洁漂亮

类型推演

借助编译器「类型推演」的能力,可以进一步简化Lambda表达式。

Collections.sort(repo, (p1, p2) ->   p1.getWeight().compareTo(p2.getWeight()));

Lambda的形式

  • 形式1:(parameters) -> exPression

Collections.sort(repo, (p1, p2) ->    p1.getWeight().compareTo(p2.getWeight()));
  • 形式2:(parameters) -> { statements; }

Collections.sort(repo, (p1, p2) -> {   return p1.getWeight().compareTo(p2.getWeight()); });

默认方法

先看看java.util.Collections.sort的实现,其中java.util.Collections是一个典型的「工具类」。

public final class Collectins {   private Collectins() {   }      public static <T> void sort(List<? extends T> l, Comparator<? super T> c) {     l.sort(c);   } } 

这样的设计是反OO,为此可以将其sort搬迁至List接口中去。

public interface List<E> extends Collection<E> {   default void sort(Comparator<? super E> c) {     ...   }   ... }

default方法类似于C++虚函数。从某种意义上看,default的引入使得Java又重新回到了「多重继承」的怀抱,为设计带来了更大的弹性。

为此,设计可重构为更加符合OO的风格。

repo.sort((p1, p2) -> p1.getWeight().compareTo(p2.getWeight()));

方法引用

借助Comparator.comparing的工厂方法,结合「方法引用」可进一步提高代码的可读性

import static java.util.Comparator.comparing;  repo.sort(comparing(Product::getWeight));

方法引用其本质是具有单一方法调用的lambda表达式的「语法糖」表示。

级联方法

需求2. 按照产品的重量降序排序

repo.sort(comparing(Product::getWeight)   .reversed());      .thenComparing(Product::getCountry));

需求3. 如果重量相同,则按照出厂国的自然序排序

repo.sort(comparing(Product::getWeight)   .reversed()   .thenComparing(Product::getCountry));

深入理解Comparator

有且仅有一个抽象方法的接口,称为「函数式接口」,使用@FunctionalInterface的注解标识。函数式接口中「抽象方法」描述了Lambda表达式的「原型」。

() -> {}也是一个合法的Lambda表达式,与Runnable接口相匹配。

也就是说,一个「函数式接口」可包含如下元素:

  • Abstract Method:有且仅有一个抽象方法

  • Default Methods0个或多个默认方法

  • Static Methods0个或多个静态方法

对照前面的列子,可洞悉Comparator设计的巧妙。

repo.sort(comparing(Product::getWeight)   .reversed());

其中,Comparator就是一个典型的函数式接口。通过「方法级联」设计了一套简单ComparatorDSL,增强了用户的表达力。

@FunctionalInterface public interface Comparator<T> {   int compare(T o1, T o2);      default Comparator<T> reversed() {     return Collections.reverseOrder(this);   }      static <T, U extends Comparable<? super U>>    Comparator<T> comparing(     Function<? super T, ? extends U> extractor) {     return (c1, c2) -> extractor.apply(c1)       .compareTo(extractor.apply(c2));   } }

其中,Comprator.compring的实现稍微有点复杂。

  • comparing是一个静态工厂方法,它生产一个Comparator<T>类型的实例;

  • comparing是一个高阶函数;

    • 接受一个函数:Function<? super T, ? extends U> extractor

    • 返回一个函数:Comparator<T>

  • comparing是一个语法糖,结合「方法引用」的机制,极大地改善了用户接口的表达力;

脚本宝典总结

以上是脚本宝典为你收集整理的Java8 Lambda本质论全部内容,希望文章能够帮你解决Java8 Lambda本质论所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。