Java8:Lambda简单实战

Lambda表达式可以理解为一种匿名函数:它没有名称,但是由参数列表函数主体返回类型,当然可能还有一个可以抛出的异常的列表

Lambda的基本语法是

(parameters) -> expression
  • 1

或(请注意语句的花括号)

(parameters) -> { statements; }
  • 1
根据上述语法规则,以下哪个不是有效的Lambda表达式?
(1) () -> {}
(2) () -> "Raoul"
(3) () -> {return "Mario";}
(4) (Integer i) -> return "Alan" + i;
(5) (String s) -> {"IronMan";}

答案:只有4和5是无效的Lambda。
(1) 这个Lambda没有参数,并返回void。它类似于主体为空的方法:public void run() {}。
(2) 这个Lambda没有参数,并返回String作为表达式。
(3) 这个Lambda没有参数,并返回String(利用显式返回语句)。
(4) return是一个控制流语句。要使此Lambda有效,需要使花括号,如下所示:
(Integer i) -> {return "Alan" + i;}。
(5)“Iron Man”是一个表达式,不是一个语句。要使此Lambda有效,你可以去除花括号
和分号,如下所示:(String s) -> "Iron Man"。或者如果你喜欢,可以使用显式返回语
句,如下所示:(String s)->{return "IronMan";}。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这里我们从一个排序问题入手——用不同的排序策略来给一个Apple列表排序,我们从一个原始粗暴的解决方法一步步简明清晰化。

这里会用到一系列概念:行为参数化,匿名类,Lambda表达式和方法引用

下面是Apple类的定义:

    public static class Apple {
        private Integer weight = 0;
        private String color = "";

        public Apple(Integer weight, String color) {
            this.weight = weight;
            this.color = color;
        }

        public Integer getWeight() {
            return weight;
        }

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

        public String getColor() {
            return color;
        }

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

        public String toString() {
            return "Apple{" + "color='" + color + '\'' + ", weight=" + weight + '}';
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

第一步:传递代码

Java 8的API已经为我们提供了一个List可用的sort方法,我们不用自己去实现它。

那么最困难的部分已经搞定了!但是,如何把排序策略传递给sort方法呢? 
sort方法的签名是这样的:

void sort(Comparator<? super E> c)
  • 1

它需要一个Comparator对象来比较两个Apple!这就是在Java中传递策略的方式:它们必须包裹在一个对象里。我们说sort的行为被参数化了:传递给它的排序策略不同,其行为也会不同

List<Apple> inventory = new ArrayList<>();
  • 1
public static class AppleComparator implements Comparator<Apple> {
        public int compare(Apple a1, Apple a2) {
            return a1.getWeight().compareTo(a2.getWeight());
        }
    }
inventory.sort(new AppleComparator());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第二步:使用匿名内部类

第一步的方案可以使用匿名内部类来进行优化,因为一个AppleComparator 比较器可能就使用一次,我们不需要单独创建一个类来实现它。

        inventory.sort(new Comparator<Apple>() {
            public int compare(Apple a1, Apple a2) {
                return a1.getWeight().compareTo(a2.getWeight());
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5

第三步:使用Lambda表达式

使用匿名内部类的缺点: 
1.它往往很笨重,占用了很多代码空间,换句话来说,它太啰嗦了。 
2.用起来让人费解,逻辑不是很清晰。 
Java 8中引入了Lambda表达式,它提供了一种轻量级的语法来实现相同的目标:传递代码。(放在我们这个问题里就是传递策略,List#sort()方法根据不同的策略(代码)来实现不同的排序)。 
在这个例子中,Comparator代表了函数描述符(T, T) -> int。因为我们比较的是苹果,所以它具体代表的就是(Apple, Apple) -> int。

inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
  • 1

因为,Java编译器可以根据Lambda出现的上下文来推断出Lamdba表达式参数的类型,那么我们的解决方案可以改写为:

inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
  • 1

到这里我们依旧不满足,Comparator具有一个叫作comparing的静态辅助方法,它可以接受一个Function来提取Comparable键值,并生成一个Comparator对象。

    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

它可以像下面这样用(注意你现在传递的Lambda只有一个参数:Lambda说明了如何从苹果中提取需要比较的键值):

Comparator<Apple> c = Comparator.comparing((Apple a) -> a.getWeight());
inventory.sort(c);
  • 1
  • 2

这里我们还可以把代码改的紧凑一些:

// 静态导包
import static java.util.Comparator.comparing;
inventory.sort(comparing((a) -> a.getWeight()));
  • 1
  • 2
  • 3

第四步:使用方法引用

方法引用就是替代那些转发参数的Lambda表达式的语法糖。你可以用方法引用让你的代码更简洁(假设你静态导入了java.util.Comparator.comparing):

inventory.sort(comparing(Apple::getWeight));
  • 1

方法引用让你重复使用现有的方法实现并直接传递它们。

恭喜你,这就是你的最终解决方案!这比Java 8之前的代码好在哪儿呢?

它比较短;它的意思也很明显,并且代码读起来和问题描述差不多:“对库存进行排序,比较苹果的重量。”

 

https://blog.csdn.net/SunTree_X/article/details/70941271

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值