Effective Java 读书笔记(三)

前言:

又来更新了,每天点儿时间来更新两个小item,其实本来可以更新三个的,但item07有些地方自己不是蛮熟悉嘛,顺带着需要花点时间看看。这里先更新item05&item06

Item05:Prefer dependency injection to hardwiring resources 优先考虑依赖注入来引用资源

在实际项目中,有许多类会依赖一个或者多个底层的资源。例子:拼写检查器需要依赖词典,因此有几种可以将其实现的方法。

1、将类实现为静态工具类
public class SpellChecker {
    private static final Lexicon dictionary=...;
    private SpellChecker(){
    }
    public boolean isValid(String word){
        //...
        return true;
    }
    //....
}

缺点:如果有多部辞典需要用的时候,需要创建多个拼写检查器修改其成员变量

2、将类实现为单例类
public class SpellChecker {
    private final Lexicon dictionary=...;
    private SpellChecker(...){
      ...
    }
  	public static INSTANCE=new SpellChecker(...);
    public boolean isValid(String word){
        //...
        return true;
    }
    //....
}

缺点:如果有多部辞典需要用的时候,需要创建多个拼写检查器修改其INSTANCE

3、通过依赖注入,不同的依赖生成不同的操作对象

代码:

public class SpellChecker {
    private final Lexicon dictionary;
    public SpellChecker(Lexicon dictionary){
        this.dictionary= Objects.requireNonNull(dictionary);
    }
    public boolean isValid(String word){
        //...
        return true;
    }
    //....
}

比较常用的代码结构吧算是。

总结:

1、静态工具类和singleton类不适合引用底层的资源类

2、不要直接在成员变量处创建资源,而是通过依赖注入

Item06:Avoid creating unnecessary objects 避免创建不必要的对象

极端的反面例子:

String s=new String(“lqh666***”);

该语句每次执行的时候都会创建一个新的string实例。但这些创建对象的动作没有必要,传递给String构造器的参数“lqh666***”本来就是一个String实例,功能等于string构造器创建的对象。

改进后:

String s=“lqh666***”;

这个版本只用了一个string实例,并且不是每次执行的时候都创建一个新的实例,在用一台虚拟机中运行的代码,只要他们包含相同的字符串字面敞亮,该对象就会被重用。

要点:

1、当一个方法中需要频繁地创建新对象,需要思考这个对象是否可以缓存。

例子:

public class RomanUtil {
    private static final Pattern ROMAN=Pattern.compile("[0-9]*");

    //每次调用都创建新的Pattern对象
    public static boolean isRomanNumeral(String s){
        return s.matches("[0-9]*");
    }

    //由于ROMAN的正则表达式不会变,所以这里缓存起来,每次都使用同一个Pattern
    public static boolean isRomanNumeral0(String s){
        return ROMAN.matcher(s).matches();
    }
}

2、当一个对象是不变的,那么他就基本可以重用

例如:

  • 适配器模式下,适配器除了委托的对象之外,没有其他状态信息,所以适配器模式中部分的适配器是不需要创建多个适配器实例的
  • Map接口的keySet()方法返回Map的Key视图,要保证每次返回的keySet功能都是相等的,且与其他返回的视图要保持更新,由内部的迭代器完成不是每个keySet都是独一,所以这里重复创建并没有意义。

3、自动装箱使得基本类型和装箱类型之间的差别变得模糊,但没有完全消除,所以使用装箱类型会额外的创建多余的对象。

什么是自动装箱拆箱?

//自动装箱
Integer total = 99;
//自定拆箱
int totalprim = total;

简单一点说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。

再细说的话请移步:https://blog.csdn.net/liuchaoxuan/article/details/80788060

这里给出结论:使用基本类型会比使用装箱类型更快。

例如:

Long sum=0L;
for(int i=0;i<10;i++){
  sum+=i;
}

上述代码使用的装箱类型,每次sum+=i的时候都会构建一个Long实例,即生成了多余的对象,我们使用long基本类型就可以完美解决,优化性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值