Effective java笔记(七),通用程序设计

45、将局部变量的作用域最小化

将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性。

Java允许在任何可以出现语句的地方声明变量(C语言中局部变量要在代码块开头声明),要使局部变量的作用域最小化,最好的方法是在第一次使用它的地方声明。局部变量的作用域从它被声明的点开始扩展,一直到外围块的结束处。

如果在循环终止之后不再需要循环变量的内容,for循环就优于while循环。for循环中变量的作用域范围更小,可以避免一些复制、粘贴错误,并且for循环更简短、可读性更强。如:

for(Element e : c) {
    doSomething(e);
}

Iterator<Element> i = c.iterator();
while(i.hasNext()) {
    doSomething(i.next());
}

若循环测试中涉及方法调用,并且每次迭代都返回相同的结果。应使用下面的方法避免每次迭代中执行冗余计算。

for(int i=0, n=upper(); i<n; i++) {
    doSomething(i);
}

46、for-each循环优先于传统的for循环

for-each循环,通过完全隐藏迭代器或索引变量,避免了调用时混乱和出错的可能。

例如:打印一对骰子的所有可能情况

enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX }
....
Collection<Face> faces = Arrays.asList(Face.values());

for(Iterator<Face> i=faces.iterator(); i.hasNext(); ) {
    for(Iterator<Face> j=faces.iterator(); j.hasNext(); ) {
        System.out.println(i.next() + " " + j.next());
    }
}

这个程序不会抛出异常,而是打印6种组合(ONE ONE 到 SIX SIX),而不是36种组合。要修正这个错误,必须在外部循环的作用域中添加一个临时变量来保存外部元素。如:

for(Iterator<Face> i=faces.iterator(); i.hasNext(); ) {
    Face temp = i.next();
    for(Iterator<Face> j=faces.iterator(); j.hasNext(); ) {
        System.out.println(temp + " " + j.next());
    }
}

若使用嵌套的for-each循环,这个错误就可以完全避免。如:

for(Face face1 : faces) {
    for(Face face2 : faces) {
        System.out.println(face1 + " " + face2);
    }
}

for-each循环不仅可以遍历集合和数组,还可以遍历任何实现了Iterable接口的对象。但有三种常见的情况无法使用for-each循环:

  • 过滤,遍历集合或数组并删除选定的元素,需要使用显式的迭代器。
  • 转换,遍历集合或数组并替换选定的元素。
  • 平行迭代,需要平行的遍历多个集合或数组(骰子打印6种组合的情况)

47、了解和使用类库

使用标准类库的好处:

  • 可以充分利用他人的使用经验
  • 不必浪费时间在一些与工作不相关的问题上
  • 性能会随着时间的推移而不断提高
  • 可以使自己的代码融入主流

java程序员应该熟练掌握和使用java.lang,java.util,java.io包中的内容。

一句话,不要重新发明轮子。

48、如果需要精确的答案,请避免使用float和double

float和double类型在执行二进制浮点运算时,不能得到完全精确的结果,它们不应该被用于需要精确结果的场合。例如:0.4 + 0.2输出结果为0.6000000000000001。 原因可以参考这篇博客 代码之谜(五)- 浮点数(谁偷了你的精度?)

解决这个问题的办法是使用BigDecimal进行计算,或转化为int、long类型(自己处理小数点)。如:

BigDecimal result = new BigDecimal("0.2").add(new BigDecimal("0.4"));

对于任何需要精确答案的计算任务,不要使用float或double。

49、基本类型优先于装箱基本类型

java中每个基本类型(int、double)都有一个对应的引用类型(Integer、Double),称作装箱基本类型。

基本类型和装箱基本类型的区别:

  1. 基本类型是值,而装箱基本类型是对象
  2. 装箱基本类型有非功能值null
  3. 基本类型更节省时间和空间

编程时应注意下面几种常见的错误:

//1. ==操作
public int compare(Integer first, Integer second) {
    return first < second ? -1 :(first == second ? 0 : 1); //compare(42,42)结果返回1
}

//2. null
Integer i;
if(i == 42) { //报空指针异常,i初始值为null
    ...
}

//3. 无意识的装箱
Long sum = 0L; //无意识的装箱,性能严重下降
for(long i=0; i<Integer.MAX_VALUE; i++ ) {
    sum += i;
}

必须使用装箱基本类型的情况:

  • 泛型中的参数化类型
  • 进行反射的方法调用时

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

如果可以使用更加合适的数据类型,或者可以编写更适当的数据类型,就应该避免用字符串来表示对象。若使用不当,字符串会比其他类型更笨拙、速度更慢、也更容易出错。不要用字符串来代替基本类型、枚举类型和聚集类型。

51、当心字符串连接的性能

不要使用字符串连接操作符+来合并多个字符串,应该使用StringBuilder的append方法。第一种方法的时间复杂度为O(n2),第二种方法的时间复杂度为O(n)。

52、通过接口引用对象

若有合适的接口类型存在,那么对于参数、返回值、变量和域,应该使用接口而不是类进行声明。这将使程序更加灵活。

53、接口优先于反射机制

反射机制提供了访问编译时未知的类的能力,对于复杂的系统编程任务,它是必要的。但它也有一些缺点,比如:丧失了编译时类型的检查、代码冗长、性能较低等。若有可能应该仅仅使用反射机制来实例化对象,而访问对象则使用编译时已知的接口或超类。

54、谨慎的使用本地方法

Java Native Interface(JNI) 允许java程序可以调用本地方法—native method,本地程序设计语言(如C或C++)编写的特殊方法。

本地方法的主要用途有:访问遗留代码库、提高系统性能、访问注册表和文件锁等。本地方法是不安全的、难于调试并且不可自由移植。应该尽量少使用或不使用本地方法。

55、谨慎的进行优化

  • 不要因为性能而牺牲合理的结构。要努力编写好的程序而不是快的程序。
  • 不要进行优化,特别是不成熟的优化。

不要费力去编写快速的程序——应该努力编写好的程序。在设计API、线路层协议和永久数据格式的时候,一定要考虑性能的因素。若系统不够快,可使用性能剖析工具找到问题的根源,并设法优化相关的部分。再多的低层优化也无法弥补算法的选择不当,所以选择一个好的算法是性能优化的根本。

56、遵循普通接受的命名惯例

java的命名惯例包含在《Java编程规范》(the java language specification)中。

泛型参数类型:T表示任意的类型,E表示集合的元素类型,K和V表示映射的键和值类型,X表示异常。任何类型的序列使用T1、T2、T3。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容