Effective java 总结8-通用编程

Effective java 总结8 - 通用编程

第57条 将局部变量的作用域最小化

java 允许在任何可以出现表达式的地方声明变量

在第一次使用它的地方进行声明

每一个局部变量都应该包含一个初始化表达式

在循环种植后不再需要循环变量的内容,for优先于while, 在for循环中定义变量,作用域即被限定在循环中,避免“剪切-粘贴”错误

使方法小而集中


第58条 for-each循环优于传统的for循环

for-each: 增强的for语句,完全隐藏迭代器或者索引变量, “:”读作在…里面

与传统的for相比没有性能惩罚, 更加简洁,灵活且预防出错

enum Suit{A, B, C, D}
enum Rank{E, F, G, H, I, J, K}

static Collection<Suit> suits = Arrays.asList(Suit.values());
static Collection<Rank> ranks = Arrays.asList(Rank.values());

List<Card> lists = new ArrayList<>();
for(Iterator<Suit> i = suits.iterator(); i.hasNext();)
    for(Iterator<Rank> j = ranks.iterator(), j.hasNext();)
        lists.add(new Card(i.next(), j.next()));
// bug : i.next()执行了N^2次
// 修改一, 用局部变量 Suit i = i.next(),在for之后, 再for之前
// 修改二: for-each
for(Suit s: suits)
    for(Rank r: ranks)
        list.add(new Card(s, r));

三种情况无法使用for-each:

  • 解析过滤 – 遍历集合,并删除选定元素
  • 转换 – 遍历列表数组,替换部分或全部元素
  • 平行迭代 – 平行地遍历多个集合

for-each可以遍历实现Iterator接口的任何对象

public interface Iterator<E> { 
	Iterator<E> iterator();
}

第59条 了解和使用类库

使用标准类库的优势

  • 可以充分利用编写类库的专家知识和他人使用经验

  • 时间专注在应用实现,而不是底层实现

  • 性能会不断提高

  • 功能不断丰富

  • 可以使自己的代码融入主流

一些应该熟悉的类库

  • java.lang java.util java.io 及其子包中的内容

  • Collections Framework 集合框架 和 Stream 类库

  • Google优秀的开源 Guava 类库


第60条 如果需要精确的答案,请避免使用float和double

float和double类型主要是为了科学计算和工程计算而设计的,它们执行二进制浮点运算,为了在广泛的数值范围上提供较为精确的快速近似计算而设计,但是并没有提供完全精确的结果

float和double尤其不适合用于货币计算

double 表示1.1 实际为 1.100000000000000088817841970012523233890533447265625

BigDecimal

// String 构造方法
BigDecimal b1 = new BigDecimal("1.1");

// Double 构造方法
BigDecimal b2 = BigDecimal.valueOf(1.1);
				= new BigDecimal(Double.toString(1.1));

// BigDecimal 与 BigInteger都是不可变得,因此每一步运算都会产生一个新的对象
BigDecimal a = new BigDecimal("1.1");
BigDecimal b = new BigDecimal("2.2");
a.add(b);
sout(a); // 结果 1.1
a = a.add(b);
sout(a); // 结果3.3

缺点:

  • 速度慢,性能不高
  • 与基本类型运算相比,复杂且不方便

int : 不超过9位10进制数字计算

long : 不超过18位10进制数字计算

BigDecimal :超过18位


第61条 基本类型优先于装箱类型

基本类型与装箱类型的区别

  1. 基本类型只有值,装箱类型则具有与值不同的同一性
  2. 基本类型只有函数值,装箱类型除了有函数值,还有null
  3. 基本类型比装箱类型更节省时间空间

同一性问题

// 一般情况下没有问题,自动进行装箱拆箱
Comparator<Integer> cp  = (i, j) -> i < j  ? -1 : (i == j ? 0 : 1);

// 特殊情况 结果期望为 0 但实际为 1
op.Compare(new Integer(42), new Integer(42));
// 对装箱基本类型运用 == 操作符几乎总是错误的,要避免装箱类型的同一性比较

//优化
Comparator<Integer> cp  = (iBoxed, jBoxed) -> {
    int i = iBoxed; // 自动拆箱
    int j = jBoxed;
    i < j  ? -1 : (i == j ? 0 : 1)
};

NULL值问题

public class Unbelievable{
    static Integer i;
    public static void main(String args[]){
        if (i == 42){...}
    }
}
// 程序抛出 NPE
// 一项操作中混合使用基本类型和装箱基本类型时,装箱类型会自动拆箱
// 如果null对象引用被自动拆箱,会抛出NullPointerException异常
// 修改 static int i; 即可

装箱类型性能问题

public static void main(Stirng[] args){
    Long sum = 0L;
    for(long = 0; i < Integer.MAX_VALUE; i++){
        sum += i; // 不断地自动拆箱装箱
    }
}
// 应该使用基本类型,装箱类型会明显导致性能下降

装箱基本类型合理的用处

  1. 作为集合中的元素、键、值
  2. 参数化类型和方法中必须使用装箱类型,java不允许使用基本类型
  3. 反射方法调用是必须使用装箱基本类型

总结

自动装箱减少了使用装箱基本类型的繁琐,但是没有减少风险,可以选择的时候,基本类型要优先于装箱基本类型


第62条 如果其他类型更适合,则尽量避免使用字符串

字符串不适合代替其他的值类型,不适合代替枚举类型,不适合代替聚合类型 (class),不适合代替能力表

public final class ThreadLocal<T>{
    public ThreadLocal(){}
    public void set(T value){}
    public T get(){}
}

如果可以使用更加合适的数据的类型,或者编写更加适当的数据类型,就应该避免使用字符串来表示对象


第63条 了解字符串连接的性能

为连接n个字符串而重复地使用字符串连接操作符,需要n的平方级时间

public String statement(){
    String result = "";
    for (int i = 0; i < num; i++)
        result += arr(i);
    return result;
}
// 使用StringBuilder 代替 操作符 “+”
public String statement(){
    StringBuilder result = new StringBuilder(num * line_width);
    for (int i = 0; i < num; i++)
        result.append(arr(i));
    return result;
}

不要使用字符串连接符来合并多个字符串


第64条 通过接口引用对象

如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型进行声明,程序会更加灵活,只有当利用构造器创建的时候需要引用这个对象的类

Set<Person> sp = new HashSet<>();

如果没有合适的接口,完全可以用类而不是接口来引用对象

  • 值类(String , BigInteger…)
  • 基于类的框架(java.io.OutputStream)
  • 类实现了接口,但也提供了接口中不存在的额外方法(类只应该用来引用实例,不能作为参数类型)

如果没有合适的接口,就用类层次结构中提供了必要功能的最小的具体类来引用对象


第65条 接口优先于反射机制

核心反射机制,java.lang.reflect包,提供了通过程序访问任意类的功能

Constructor, Method, Field实例可以通过反射访问底层类的构造方法, 方法和域

反射的代价

  • 损失了编译时类型检查的优势
  • 执行反射访问所需要的代码笨拙且冗长
  • 性能损失

如果只是以非常有限的形式使用反射机制,用少许代替获得更多收益

public static void main(String[] args) throws ...{
    Class<? extends Set<String>> c = null;
    c = (Class <? extends Set<String>>)Class.forName(args[0]);

    Constructor<? extends Set<String>> cons = null;
    cons = c.getConstructor();

    Set<String> s = cons.newInstance();
    s.add("a");
    s.add("b");
    System.out.println(s);
}
// args[0] : java.util.TreeSet

第66条 谨慎地使用本地方法

本地方法:本地编程语言编写的方法(C、C++)

JNI(java native interface) 允许java应用程序调用本地方法,提供了访问特定于平台的机制的能力,访问注册表等,此外,编写应用程序中注重性能的部分,能提高性能

但不建议使用本地方法来提高性能:

  • JVM越来越快
  • 本地方法有严重的缺陷,不安全
  • 程序不再能跨平台,不能轻松移植
  • 可能降低性能,因为垃圾回收不是自动的
  • 本地程序的一个Bug都可能破坏整个程序

第67条 谨慎地进行优化

不成熟的优化才是一切问题的根源

  • 努力编写好的程序,而不是快的程序,好的程序,速度自然随之而来
  • 努力避免限制性能的设计决策,设计API、交互层协议,永久数据结构要考虑性能因素
  • 要考虑API设计决策的性能后果,选择好的算法更为重要
  • 每次试图优化前后,要对性能进行测量,可以借助性能剖析器

第68条 遵守普遍接受的命名惯例

包和模块

名称应该是层次状的,用句号分割,一般都为小写字母, eg: cn.com.sge; com.google。 不能以java、javax开头

通常不超过8个字符,可以接受缩写,eg: awt, util

类和接口

包含一个或多个单词,每个单词首字母大写,尽量避免使用缩写, eg: List, FutureTask

方法和域

第一个字母应该小写, eg: remove, add。

常量域例外,应该是一个或多个全大写字母(<唯一推荐用下划线>下划线连接)组成,值是不可变的 eg: VALUES, A_B_C

局部变量名称允许缩写,需要联系上下文

类型参数

  • T:任意类型
  • K,V:映射的键值
  • E: 集合的元素类型
  • X: 异常
  • R: 返回类型

语法命名惯例

可以被实例化的类用一个名词或名词短语:Thread, PriorityQueue

不可实例化的工具类用复数名词命名: Collectors, Collections

接口命名与类类似,或以able,ible结尾:Runnable, Iterable, Accessable

指定某个动作的方法用用词或动词短语:append, add

返回boolean值的方法:is开头,isDigit, isEmpty

转换对象类型的实例方法:toType : toString, toArray

返回视图: asType: asList

返回与调用对象同值的基本类型方法: typeValue: intValue

静态工厂的常用名称: from, of, valueoOf, instance, getInstance, newInstance, getType, newType


的工具类用复数名词命名: Collectors, Collections

接口命名与类类似,或以able,ible结尾:Runnable, Iterable, Accessable

指定某个动作的方法用用词或动词短语:append, add

返回boolean值的方法:is开头,isDigit, isEmpty

转换对象类型的实例方法:toType : toString, toArray

返回视图: asType: asList

返回与调用对象同值的基本类型方法: typeValue: intValue

静态工厂的常用名称: from, of, valueoOf, instance, getInstance, newInstance, getType, newType


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值