带你快速看完9.8分神作《Effective Java》—— Lambda 和 Stream篇(小王工作里用的很多)

🍊 Java学习:Java从入门到精通总结

🍊 Spring系列推荐:Spring源码解析

📆 最近更新:2021年12月16日

🍊 个人简介:通信工程本硕💪、阿里新晋猿同学🌕。我的故事充满机遇、挑战与翻盘,欢迎关注作者来共饮一杯鸡汤

🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!

豆瓣评分9.8的图书《Effective Java》,是当今世界顶尖高手Josh Bloch的著作,在我之前的文章里我也提到过,编程就像练武,既需要外在的武功招式(编程语言、工具、中间件等等),也需要修炼心法(设计模式、源码等等)学霸、学神OR开挂

我也始终有一个观点:看视频跟着敲代码永远只是入门,从书籍里学到了多少东西才决定了你的上限。

在这里插入图片描述

我个人在Java领域也已经学习了近5年,在修炼“内功”的方面也通过各种途径接触到了一些编程规约,例如阿里巴巴的泰山版规约,在此基础下读这本书的时候仍是让我受到了很大的冲激,学习到了很多约定背后的细节问题,还有一些让我欣赏此书的点是,书中对于编程规约的解释让我感到十分受用,并愿意将他们应用在我的工作中,也提醒了我要把阅读JDK源码的任务提上日程。

最后想分享一下我个人目前的看法,内功修炼不像学习一个新的工具那么简单,其主旨在于踏实,深入探索底层原理的过程很缓慢并且是艰辛的,但一旦开悟,修为一定会突破瓶颈,达到更高的境界,这远远不是我通过一两篇博客就能学到的东西。

接下来就针对此书列举一下我的收获与思考。

不过还是要吐槽一下的是翻译版属实让人一言难尽,有些地方会有误导的效果,你比如java语言里extends是继承的关键字,书本中全部翻译成了扩展 就完全不是原来的意思了。所以建议有问题的地方对照英文原版进行语义上的理解。

没有时间读原作的同学可以参考我这篇文章。


42 Lambda优先于匿名类

自从JDK 1.1于1997年发布以来,创建函数对象的主要手段就是匿名类。下面代码是按照字符串⻓度顺序对列表进行排序,使用匿名类创建排序的比较方法:

Collections.sort(words, new Comparator<String>() {
   
	public int compare(String s1, String s2) {
   
		return Integer.compare(s1.length(), s2.length());
	}
});

匿名类适用于需要函数对象的经典面向对象设计模式,特别是策略模式Comparator接口代表一种排序的抽象策略;上面的匿名类是排序字符串的具体策略

在Java 8中,“带有单个抽象方法的接口”是特殊的,他们被称作函数式接口,Java允许利用Lambda表达式创建这些接口的实例。

Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));

Lambda的类型是Comparator <String>,其参数s1,s2的类型是String,返回值类型int全都没有出现在代码里

编译器使用一个叫类型推断的过程从上下文中推断出这些类型。

如果编译器产生错误消息,无法推断出Lambda参数的类型,那就手动指定它。


如果用Lambda表达式代替Comparator的构造方法,代码会更加简练:

Collections.sort(words, comparingInt(String::length));

如果用Java 8中List接口里的sort方法,代码还可以更简洁:

words.sort(comparingInt(String::length));

Java中增加了Lambda之后,使得之前不能使用函数对象的地方现在也能用了。例如,以34条里的Operation枚举类型为例:

public enum Operation {
   
    PLUS("+") {
   
        public double apply(double x, double y) {
   
            return x + y;
        }
    },
    MINUS("-") {
   
        public double apply(double x, double y) {
   
            return x - y;
        }
    },
    TIMES("*") {
   
        public double apply(double x, double y) {
   
            return x * y;
        }
    },
    DIVIDE("/") {
   
        public double apply(double x, double y) {
   
            return x / y;
        }
    };

    private final String symbol;

    Operation(String symbol) {
   
        this.symbol = symbol;
    }

    @Override
    public String toString() {
   
        return symbol;
    }

    public abstract double apply(double x, double y);
}

使用Lambda改造的话,只要给每个枚举常量的构造器传递一个实现其行为的Lambda即可:

public enum Operation {
   
    PLUS("+", (x, y) -> x + y),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    private final String symbol;
    private final DoubleBinaryOperator op;

    Operation(String symbol, DoubleBinaryOperator op) {
   
        this.symbol = symbol;
        this.op = op;
    }

    @Override
    public String toString() {
   
        return symbol;
    }

    public double apply(double x, double y) {
   
        return op.applyAsDouble(x, y);
    }
}

构造方法将Lambda存储在实例属性中,apply 方法将调用转发给Lambda,代码量更少,逻辑也更清晰。


使用Lambda需要注意的地方是:Lambda没有名称和文档;如果计算比较复杂,或者代码量超过几行,就不要用Lambda了

Lambda表达式一行是最好的,三行是极限!不能再多了

传递给枚举构造方法的参数是在静态环境中计算的。因此,枚举构造方法中的Lambda表达式不能访问枚举的实例成员。如果枚举类型具有难以理解的特殊方法,使用原先的实现方式仍是首选。


匿名类在Lambda时代并未过时,可以依据以下几点来进行选择:
1. 如果想创建抽象类的实例,可以用匿名类来完成

2. 如果一个接口有多个抽象方法,创建实例要用匿名类

3. Lambda无法获得对自身的引用
在Lambda中,关键字this指向外围实例,这通常是我们想要的


不要序列化一个 Lambda 或 匿名类实例,如果想要可序列化的函数对象,如Comparator,就使用私有静态嵌套类的实例。


43 方法引用优先于Lambda

如果方法引用看起来更简短更清晰,就用方法引用;否则还是用Lambda


Java提供了一种生成函数对象的方法,比lambda还要简洁&#x

  • 40
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 41
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王曾是少年

如果对你有帮助,欢迎支持我

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值