OracleLambda表达式实战分析(上篇)

lambda表达式是Java
8中最好特别语言改变了,允许我们将函数当作参数传递给其他方,简而言之便是落实了:行为参数化。

lambda表达式是函数式编程里要之概念。现在本人尝试通过一个事例来说明Lambda表达式的演化过程

一个果农的要求变动

生只应用程序是援果农了解自己之库存的。这员果农可能想闹一个找寻库存中有绿色苹果的
功能。但至了亚天,他或会见报你:“其实自己还惦记搜寻来装有重量逾150克之苹果。”又过了零星上,农民以跑回去补充道:“要是本身得查找来富有既是绿色,重量为超越150克的苹果,那即便最好
棒了。”

公如果怎样对这样不断转变之求?

需变动过程

1. 果农查找库存中兼有绿色苹果

实现代码如下:

    /**
     * 筛选绿苹果
     * @param rawAppleList
     * @return
     */
    private static List<Apple> filterGreenApples(List<Apple> rawAppleList){
        List<Apple> result = new ArrayList<>();
        if(rawAppleList == null || rawAppleList.isEmpty()){
            return result;
        }
        for(Apple apple : rawAppleList){
            if("Green".equalsIgnoreCase(apple.getColor())){
                result.add(apple);
            }
        }
        return result;
    }

2. 果农查找库存中拥有红色苹果

求从寻找绿苹果变成了查找红苹果,可以推测之后农户来或使查询黄苹果,因此新增一个颜料入参

    /**
     * 筛选任意一颜色的苹果
     * @param rawAppleList
     * @param color
     * @return
     */
    private static List<Apple> filterApplesWithColor(List<Apple> rawAppleList, String color){
        List<Apple> result = new ArrayList<>();
        if(rawAppleList == null || rawAppleList.isEmpty()){
            return result;
        }

        for(Apple apple : rawAppleList){
            if(color.equalsIgnoreCase(apple.getColor())){
                result.add(apple);
            }
        }
        return result;
    }

3. 果农查找库存中越150限的更苹果

方的入参增加一个形参:重量

/**
 * 筛选出大苹果
 * @param rawAppleList
 * @param weight
 * @return
 */
private static List<Apple> filterApplesWithWeight(List<Apple> rawAppleList, int weight){
    List<Apple> result = new ArrayList<>();
    if(rawAppleList == null || rawAppleList.isEmpty()){
        return result;
    }

    for(Apple apple : rawAppleList){
        if(weight < apple.getWeight()){
            result.add(apple);
        }
    }
    return result;
}

4. 果农查找库存中的绿苹果和跨越150限之再次苹果

引入意味着重量和颜料之入参

/**
 * 通过颜色和重量筛选苹果
 * @param rawAppleList
 * @param color
 * @param weight
 * @return
 */
private static List<Apple> filterApplesByProperty(List<Apple> rawAppleList, String color, int weight){
    List<Apple> result = new ArrayList<>();
    if(rawAppleList == null || rawAppleList.isEmpty()){
        return result;
    }

    for(Apple apple : rawAppleList){
        if(color != null && weight > 0) {
            if (weight < apple.getWeight() && color.equalsIgnoreCase(apple.getColor())) {
                result.add(apple);
            }
        }
    }
    return result;
}

果农之后想对苹果之差属性做筛选,比如大小、形状、产地,品种等,怎么处置?

一旦及时号果农想多只属性组合查询,做还复杂的询问,比如革命的根源福建的死去活来苹果,又欠怎么处置?

应针对这些需要,需要为艺术里增长很多参数,有没有发出再度好之包裹?

接口

上述过程,复制了绝大多数底代码来落实遍历查询。如果您想使反筛选遍历方式来提升性也?
那即便得改所有办法的实现,而无是只有变动一个,这代价最要命了。我们用复用,我们得抽象。

领取抽象要确定抽象的有,确定要求我们针对需的改动和未来之演化过程有旁观者清的认识,基于这种认识来确定抽象。

运接口定义一个泛方法,不同的判断标准提交不同之兑现类似来形成。一潮判断标准作为一种植表现,不同之落实类似表达不同的淘行为。

/**
 * 筛选苹果
 * @param rawAppleList
 * @param predicate
 * @return
 */
private static List<Apple> filterApples(List<Apple> rawAppleList, IApplePredicate predicate){
    List<Apple> result = new ArrayList<>();
    if(rawAppleList == null || rawAppleList.isEmpty()){
        return result;
    }
    for(Apple apple : rawAppleList){
        if(predicate.test(apple)){
            result.add(apple);
        }
    }
    return result;
}

这时,filterApples方法的行事的歧异在我们污染于IApplePredicate的贯彻类似的所作所为,filterApples行为被参数化了。

匿名内部类

在采用过程被,发现只要判断标准发生多种植,会转变多独实现类似。使用匿名内部类能化简代码,减少啰嗦

List<Apple> apples = filterApples(RAW_APPLE_LIST, new IApplePredicate() {
    @Override
    public boolean test(Apple apple) {
        if ("Red".equalsIgnoreCase(apple.getColor())
                && 150 < apple.getWeight()
                && "福建".equals(apple.getProducingArea())) {
            return true;
        }
        return false;
    }
});

果农需要查询什么,我传入不同筛选标准的匿名内部类。

使用Lambda表达式

下匿名内部类在一样段模板代码,我们意在并这么的模板代码都无,让代码更简洁些。

然后,简洁性和易读性这二者看起是抵触,简洁就表示代码量少,往往也带来不错读。

Oracle工程师提出了相同种植处理方式:
Lambda表达式来化解简洁性和易读性的扑。

filterApples(RAW_APPLE_LIST, (Apple apple) -> { 
   if("Green".equalsIgnoreCase(apple.getColor())
           && 150 > apple.getWeight()){
      return true;
   }
   return false;
});

lambda表达式详解

lambda表达式组成部分

行使匿名内部类与lambda表达式对比

    private static void testFilterAnonymous(){
        filterApples(RAW_APPLE_LIST, new IApplePredicate() {
            @Override
            public boolean test(Apple apple) {
                return "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight();
            }
        });
    }

    private static void testFilterApplesLambda(){
        filterApples(RAW_APPLE_LIST, (Apple apple) -> "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight());
    }

lambda表达式由参数,箭头和方法体三有组成.

一个艺术有入参,返回值和办法实现。匿名内部类的里的test方法的入参,作为lambda箭头左侧有,(当入参达到一定量只以上时使用圆括声泪俱下),test方法实现作为了lambda箭头右侧有,test方法的回
值用右侧表达式返回值来表述。当需要差不多漫长告句时,需要为此花括号{},并出示声明回的花色

apple -> {
            println("");
            return "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight();
        };

lambda表达式是起返路的,是对应之接口名

Predicate<Apple> filter = (Apple apple) -> "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight();

嗬地方使用lambda表达式

来函数式接口的地方即足以应用lambda表达式。

函数式接口:单独定义了一个华而不实方法的接口。@FunctionalInterface

我们耳熟能详的Runnable,Callback,Comparator, Comparable都是函数式接口

形容lambda表达式时,入参数量,各个参数的项目和表达式返回路怎么规定为?这些信,需要熟悉对应之函数式接口。

Java8引入了有的初的函数式接口,常见的如下

  • Predicate<T>

      boolean test(T t);
    
  • Consumer<T>

      void accept(T t);
    
  • Supplier<T>

      T get();        
    
  • Function<T, R>

      R apply(T t);
    
  • BiFunction

      R apply(T t, U u);  
    
  • UnaryOperator<T>

      public interface UnaryOperator<T> extends Function<T, T> {}
    
  • BinaryOperator<T>

      public interface BinaryOperator<T> extends BiFunction<T,T,T> {}
    
  • Comparator

      int compare(T o1, T o2);
    

说明:Java库提供的这些接口,没有充分处理,因此,要么我们自己定义函数式接口抛来同会,要么在动这些体系提供的函数式接口写Lambda表达式时,自己捕获异常

lambda的连带概念

对象项目

lambda表达式返回路,也就函数式接口

函数描述吻合

按照,上文的Predicate<Apple>的虚幻方法的函数描述符为:

    (Apple) -> Boolean  

Lambda表达式的种检查

Java编译器如何检查Lambda表达式的类?

  1. 每当调用lambda表达式处,找到对象项目,即函数式接口
  2. 找到以函数式接口里,抽象方法函数名叫,入参,返回值,生成函数描述符号。
  3. 泛方法的函数描述称和lambda表达式的签约比对

同样的Lambda表达式,可以生出异返回路

看下的例证

Predicate<Apple> appleFilter = (Apple apple) -> "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight();

Function<Apple, Boolean> appleFilter1 = (Apple apple) -> "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight();

一律之Apple->Boolean 返回路可以是Predicate,也可是Function

花色推断

使泛型的路推断,可以省略lambda表达式入参的路声明,比如

Predicate<Apple> filter = apple ->
         "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight();


filterApples(RAW_APPLE_LIST,  apple -> "Green".equalsIgnoreCase(apple.getColor()) && 150 > apple.getWeight());

法引用

术引用能管用之简化lambda表达式Oracle,我们来选个例证

创办一个草莓类,Strawberry

public class Strawberry {

    private int weight;
    private String color;

    public Strawberry() {
    }

    public Strawberry(int weight) {
        this.weight = weight;
    }

    public Strawberry(int weight, String color) {
        this.weight = weight;
        this.color = color;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Strawberry{" +
                "weight=" + weight +
                ", color='" + color + '\'' +
                '}';
    }
}

public class TransferUtils {

    public static int doubleValue(int value){
        return 2 * value;
    }

    public void tripleOver(int a){
        System.out.println(String.valueOf(3 * a));
    }

}

构造函数的点子引用

无论参构造

Supplier<Strawberry>  strawberrySupplier = Strawberry::new;
Strawberry strawberry = strawberrySupplier.get();

一个参数的构造

IntFunction<Strawberry> f = Strawberry::new;
Strawberry strawberry = f.apply(10);

零星独参数的组织

BiFunction<Integer, String, Strawberry> biFunction = Strawberry::new;
Strawberry strawberry = biFunction.apply(20, "RED");

静态方法

类名::方法名

/**
     * 静态方法引用
     */
    private static void testMRStatic(){
        List<Integer> list = Arrays.asList(1, 2, 3, 4);
        List<Integer> collect = list.stream()
                .map(TransferUtils::doubleValue)
                .collect(Collectors.toList());
        println(collect);
    }

实例的章程引用

  • 无入参的实例方法,格式和静态方法引用

      String::length
    

这种以会生一个谜:实例的计引用为什么会因此类名来引用?其实这里要调用了实例的艺术,上文的实例是字符串对象。

    /**
     * 实例方法引用无参方法
     */
    private static void testMRObject(){
        Arrays.asList(new Strawberry(21), new Strawberry(23)).forEach(Strawberry::displayWeight);
    }
  • 带走参的实例方法

    类实例名::方法名

    /**
     * 实例方法引用有参方法
     */
    private static void testMRObject2(){
        TransferUtils transferUtils = new TransferUtils();
        Arrays.asList(1, 2, 3, 4).forEach(transferUtils::tripleOver);
    }

练习题

起同一箱子东港九九草莓,找到中最要命之同一颗?(可学所待的具有数据)

小结

lambda演化路径

接口 –》匿名内部类–》Lambda表达式

题材回顾

  1. 自Java7到Java8,lambda表达式经历了哪些的逻辑演化?
  2. lambda表达式能为此在怎样状况?
  3. lambda表达式和匿名内部类是什么关联?
  4. 方法引用如何简化lambda表达式?

lambda表达式还可以复合使用,还足以在策略模式,模板方法,观察模式(接口回调)等设计模式中以

连锁的代码,已上传到Github
代码传送门

参照的素材

简书:【译】Java
8的初特点—终极版

书籍:Java8实战

书:Java8套数式编程

相关文章