IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Effective Java 学习笔记(三) -> 正文阅读

[Java知识库]Effective Java 学习笔记(三)

条款5:优先使用依赖注入而非硬连接资源

很多类需要依赖资源。比如一个SpellChecker类检查拼写依赖于字典:

public class SpellChecker {
    private final static Lexicon dictionary = ...;

    private SpellChecker() {} //Noninstantiable

    public static boolean isValid(String word) {
        // Do something
    }
    public static List<String> suggestions(String typo) {
        // Do something
    }
}

但是,每个语言都有自己的字典,而且特殊词汇需要特殊字典,只有这一个字典是不行的。当类的行为由硬连接资源参数决定时,静态工具类和单例类并不适用。一种可以满足需求的方法是依赖注入,即当创建新实例时将资源传入构造器内:

public class SpellChecker {
    private final Lexicon dictionary = ...;

    public SpellChecker(Lexicon dictionary) {
        this.dictionary = Objects.requireNonNull(dictionary);
    }

    public static boolean isValid(String word) {
        // Do something
    }
    public static List<String> suggestions(String typo) {
        // Do something
    }
}

虽然依赖注入可以显著提高灵活性和可测试性,它也会让有几千个依赖的大型项目变得很杂乱。当然,使用依赖注入框架(Dagger, Guice, Spring等)可以轻松解决此问题。


条款6:避免创建不必要的对象

为了避免资源浪费,我们应尽量重复使用一个对象而非创建一个等价的对象。当对象是不可变对象时总能被重复使用。下面是一个错误的例子:

String s = new String("Hello world");

大家都知道这样是不对的,String不用new,也不应当new出来,不然每次调用都会多出一个多余的没有必要的String实例。正确的做法是:

String s = "Hello world";

这保证了当字面量相同时,String对象的重复使用。

我们可以通过使用静态工厂方法(条款1)来避免创建不必要的对象,比如用Boolean.valueof()替代Boolean()。

对于一些创建开销很大的对象来说,我们最好缓存它以达到复用并节约资源的目的。不幸的是,我们难以察觉到这些对象被创建了。例如:

static boolean isRomanNumeral(String s) {
        return s.matches("^(?=.)M*(C[MD]|D?C{0,3})"
                + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}

看上去没有问题?实际上每次调用该方法时,都会创建一个Pattern实例且用一次就销毁。每次创建Pattern实例都会有巨大的开销,因为需要把正则表达式编译成有穷自动机。所以,上面的方法应当优化为:

public class RomanNumerals {
    private final static Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})"
            + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    public static boolean isRomanNumeral(String s) {
        return ROMAN.matcher(s).matches();
    }
}

当对象是不可变对象时,显而易见能被安全复用,但还有其他一些情况也能复用,但不是这么的明显,甚至是违反直觉的。比如适配器模式(adapters)或叫视图(view),因为适配器的状态并不会超出原有对象的状态,同一个对象同一个适配器无需创建更多实例。例如,Map的keySet方法返回一个Map对象的Set视图,包含Map的所有key。对于给定的Map对象,每次调用keySet可能返回的是一样的Set实例。

还有一件事——自动装箱也会创建不必要对象。自动装箱模糊了基本类型和装箱类型的界限,但并不是消除了。下面的例子有极大的性能提升空间:

private static long sum() {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; ++i) {
            sum += 1;
    }
    return sum;
}

因为用的是Long而不是long,程序创建了2^31个不必要的Long实例!!所以,优先使用基本类型而非装箱类型,且注意意料之外的自动装箱。

本条款主要针对于创建开销很大的对象。开销小的对象创建就创建了,如果能提升程序清晰性、简洁性和功能性反而是很好的事。

除非对象真的是很重量级,开销巨大,不要维护自己的对象池!这样对象池只会起到画蛇添足的作用。一个恰当正确地使用对象池例子是数据库链接,这真的足够重量,所以需要提高对象复用。

本条款与条款50 需要时使用保护性拷贝表面上互相冲突,但实际上,一方面,程序中要避免创建冗余的对象,以减少资源占用;另一方面,在必须创建对象时,那就去创建,以保证程序的安全性和健壮性。程序要兼顾性能和安全

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-20 18:15:31  更:2021-11-20 18:17:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:37:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码