本章主要讨论语言的具体内容。它讨论了局部变量的处理、控制结构、库的使用、各种数据类型的使用,以及使用反射和本地方法。最后,讨论了优化和命名约定

Item 45:最小化局部变量作用域

作用域:一个花括号{}包裹起来的区域

此条例同Item13相似:最小化类和成员变量的访问权限

Java允许你在任何地方声明变量,但是最重要的是在首次使用的地方声明变量,并初始化

循环提供了一种实现此种方式的机制,而且for循环比while循环好,如

for (Element e : c) {

doSomething(e);

}

//before JDK1.5

for (Iterator i = c.iterator(); i.hasNext(); ) {

doSomething((Element) i.next());

}

为什么for比while好呢?

//bad

Iteratori = c.iterator();

while (i.hasNext()) {

doSomething(i.next());

}

...

Iteratori2 = c2.iterator();

while (i.hasNext()) { // BUG! 应该是i2

doSomethingElse(i2.next());

}

当我们写一个差不多的代码,从一个地方copy过来的时候,很有可能忘记修改某个变量值(如i2),它不会在编译期报错,我们很可能长时间遗留这个bug

使用for循环可以避免这个bug

for (Iteratori = c.iterator(); i.hasNext(); ) {

doSomething(i.next());

}

...

// Compile-time error - cannot find symbol i

for (Iteratori2 = c2.iterator(); i.hasNext(); ) {

doSomething(i2.next());

}

这就是最小化作用域的好处

Item 46: Prefer for-each loops to traditional for loops

对于不需要下标来做特殊操作的遍历,推荐使用增强for循环

你能发现下面的bug吗?

enum Suit { CLUB, DIAMOND, HEART, SPADE }

enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,

NINE, TEN, JACK, QUEEN, KING }

...

Collectionsuits = Arrays.asList(Suit.values());

Collectionranks = Arrays.asList(Rank.values());

Listdeck = new ArrayList();

for (Iteratori = suits.iterator(); i.hasNext(); )

for (Iteratorj = ranks.iterator(); j.hasNext(); )

deck.add(new Card(i.next(), j.next()));

...

...

...

...

...

...

发现不了也不要难过,很多有经验的程序员也会犯这个错误

原因在于i.next()会被重复调用,导致结果异常

可以修复如下

for (Iteratori = suits.iterator(); i.hasNext(); ){

Suit suit = i.next();

for (Iteratorj = ranks.iterator(); j.hasNext(); )

deck.add(new Card(suit, j.next()));

}

虽然解决了问题,但是很丑,更简洁的写法如下

for (Suit suit : suits)

for (Rank rank : ranks)

deck.add(new Card(suit, rank));

尽可能的使用增强for循环

Item 47: Know and use the libraries

不要重复造轮子

如果需要一个常用的功能,去发现一个库并使用它,往往比自己写的要好

因为库会随着时间推移更新迭代越来越好,自己也节约了时间

这并不会评论一个人的能力

Item 48: Avoid float and double if exact answers are required

当需要一个精确的答案时,避免使用float或double类型的变量

float或double是为了科学和工程计算而设计的,特别不适用于货币计算

推荐使用int或long代替

Item 49: Prefer primitive types to boxed primitives

使用原始类型替代装箱类型

byte short char int long float double boolbean等是Java中的基本类型,也有对应的装箱类型,如 Integer, Double, and Boolean.应当谨慎对待这两者之间的差别

首先第一个差别,原始类型仅仅包含对应的值,装箱类型既包含对应的值也有对应的引用,第二个差别是装箱类型有可能为null,第三个差别是原始类型在时间和空间消耗中更高效

Item 50: Avoid strings where other types are more appropriate

如果有更合适的类型,避免使用String

string被设计成描述文本类型的数据,而且干得很好,本章主要讨论将string用于其它情况的错误用法

string不能替代值类型 如果我们正在等待键盘的输入,或者从网络获取某个值,我们很方便的使用string作为接收类型,但是如果我们输入的是数字或者真假值的话,对应的int或boolean能更好的标识输入 虽然这条规则很明显,但是经常被违反

string不能替代枚举 如Item30:枚举讨论的那样,对于静态常量使用枚举

string不能替代聚合字符

String compoundKey = className + "#" + i.next();//bad

我们经常写上述代码,这样的写法有很多缺点.如果我们想使用某一部分字段需要解析字符串,很耗时而且容易出错.String提供的equals,compareTo等方法也不能使用

比较好的方式是写一个静态内部类来表示聚合字符

static class CompoundKey{

private String className;

private String next;

...

}

Item 51: Beware the performance of string concatenation

考虑字符连接(+)的性能

使用(+)能很方便的拼接若干个字符串,但是我们也要考虑到开销

如下两个代码都是拼接字符

//方式一

public String statement() {

String result = "";

for (int i = 0; i < numItems(); i++)

result += lineForItem(i); // String concatenation

return result;

}

//方式二

public String statement() {

StringBuilder b = new StringBuilder(numItems() * LINE_WIDTH);

for (int i = 0; i < numItems(); i++)

b.append(lineForItem(i));

return b.toString();

}

当numItems()==100;lineForItem(i)返回80个长度的字符时,在作者的机器上方式二比方式一快85倍

如果我们需要拼接大量字符时,使用StringBuilder代替

Item 52: Refer to objects by their interfaces

使用接口代替对象引用

如果有一个合适的接口来描述当前类的时候使用这个接口来引用,如

// Good - uses interface as type

Listsubscribers = new Vector();

// Bad - uses class as type!

Vectorsubscribers = new Vector();

如果你养成了这个习惯,那么你的代码将会更灵活

有几种情况不能使用接口

1.没有合适的接口声明

2.接口中没有想要的某个方法

3.使用的类集成自framework,并且是一个抽象类

Item 53: Prefer interfaces to reflection

使用接口代替反射

反射核心类java.lang.reflect提供了对加载类信息的访问

例如,Method.Invoke允许在任何类的任何对象上调用任何方法(受通常的安全约束)。 即使编译后的类不存在,也允许一个类使用另一个类。然而,这种力量是有代价的。

你不能在编译时检查出异常 如果你使用了对应的反射操作,在发生异常时,只有在运行时才能发现

阅读性极差

性能有影响 使用反射比普通调用要慢些,因为受很多因素的影响,慢多少很难说,在作者的机器上,速度差在两倍到五十倍不止

反射核心用在基于组件设计的应用,为了按需加载类,使用反射找到对应的类构造与否;普通应用尽量不要使用反射,找到代替的接口或者父类对象

Item 54: Use native methods judiciously

明智地使用本地方法

JNI允许Java调用C或C++写的本地方法

从历史上看,本地方法有三种主要用途。

1.它们提供了对特定于平台的设施的访问,例如注册表和文件锁。

2.他们提供了对旧代码库(Java想使用历史上C或C++写的库)

的访问,可以反过来提供对旧数据的访问。

3.使用本地方法用本地语言编写应用程序关键部分,以提高性能。

Java平台在不断发展,访问特定平台设施,使用Java提供的工具类就可做到,而且也不建议使用本地方法来提升程序性能

使用本地方法有严重的缺点

1.本地语言是不安全的,会受机器内存错误的影响

2.依赖于平台,不便于移植

3.本地代码很难调式

4.访问本地代码开销很大

5.本地代码不宜阅读

总之,要再三思考是否使用本地代码,如果需要使用以前的代码库,请尽可能减少本地代码片段并加强测试,很小很小的本地代码错误将破坏你的整个程序

Item 55: Optimize judiciously

明智的优化

有三个人人都应该知道的优化格言

More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason—including blind stupidity.

—William A. Wulf [Wulf72]

更多的计算罪恶是以效率的名义犯下的(不一定要达到这一目的),而不是因为任何其他单一的原因-包括盲目的愚蠢

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

—Donald E. Knuth [Knuth74]

我们应该忽略小效率,大约百分之97的情况下,邪恶之源就是过早优化

We follow two rules in the matter of optimization:

Rule 1. Don’t do it.

Rule 2 (for experts only). Don’t do it yet—that is, not until you have a

perfectly clear and unoptimized solution.

—M. A. Jackson [Jackson75]

关于优化遵循如下两个原则:

原则1.别这样做

原则2.(仅对专家而言).还不要做,直到你找到一个清晰的解决方案或者一个未优化的解决办法

不要为了性能而损坏架构,致力于写出好的程序而不是快的程序,如果一个好的程序还不够快,它的架构会允许优化.

这并不意味着当你的程序完后不需要优化,你应该在设计阶段就考虑到性能

尽量避免影响性能的设计,已经实现好的组件很难在改变,尤其是API,数据结构,多方约定好的协议

考虑好API使用效果,设计一个可变的类可能会导致后续使用中出现过多的深拷贝,造成对象分配的额外开销

API的设计对性能有很真实的影响,如java.awt.Component中的getSize()方法,每调用一次就会返回一个新的 Dimension 实例(JDK1.2版本已经修复),虽然分配一个实例的开销很小,但是成百上千次调用也会对程序有严重影响

幸运的是,好的API设计自然带来了好的性能

总之,致力于写出好的程序,快随之而来 当做出一部分改变后就要测量代码的性能,对于Android来说内存,卡顿,anr等方面

参考DDMS性能调优

Item 56: Adhere to generally accepted naming conventions

遵循公共的命名规范,参考阿里巴巴发布的Android手册

上一章:方法

下一章:异常

java最小访问原则_Android基础进阶之EffectiveJava翻译系列(第七章:通用原则)相关推荐

  1. java程序设计基础_陈国君版第五版_第七章例题

    java程序设计基础_陈国君版第五版_第七章例题 class Cylinder {private double radius;private int height;private double pi ...

  2. java adt入门教程_Android基础入门教程目录

    第一章:环境搭建与开发相关(已完结 10/10) https://blog.csdn.net/coder_pig/article/details/50000773 Android基础入门教程--1.1 ...

  3. 安卓的java无法访问网络_Android网络访问的基本方法

    Android访问网络的两种主要方式: 1.标准Java接口(java.net) ----HttpURLConnection,可以实现简单的基于URL请求.响应功能: 2.Apache接口(org.a ...

  4. java override 访问权限_java基础之——访问修饰符(private/default/protected/public)

    1. 访问修饰符介绍 java中的访问修饰符包含了四种:private.default(没有对应的保留字).protected和public.它们的含义如下:private:如果一个元素声明为priv ...

  5. 最新java初级高级,python基础进阶,机器学习视频资料

    我是在校口碑,现在整理了一些编程,java,python,框架,大数据资料,适用于小白和大牛!! 转载于:https://blog.51cto.com/13135855/2342878

  6. java基础实战练习_JAVA入门第三季第七章实战练习

    首先,先创建一个Gammer类与一个Poker类. /* * Gammer类包含int类型的id属性与String类型的name属性! * id用int类型是为了测试后面创建用户时输入异常的情况. * ...

  7. java狗具有特别的接飞盘的方法_java第七章 多态 课堂笔记/作业

    什么是多态: 用同一个引用类型,使用不同的实例,得到不同的结果 实现对台的三个要素是: 继承.方法重写.父类引用指向子类对象 1.使用多态时:是使用父类的类型,但是对象还是子类的对象 2.如果子类不重 ...

  8. 零基础学前端开发技术之第七章 浮动塌陷

    知识点: 1.浮动塌陷的概念 2.浮动塌陷的解决 1:浮动塌陷的概念 <!DOCTYPE html> <html><head><meta charset=&q ...

  9. MICK-SQL基础教程(第二版)第七章 集合运算

    第七章 集合运算 表的加减法 通过集合运算,可以得到两张表中记录的集合或者公共记录的集合,又或者其中 某张表中的记录的集合.像这样用来进行集合运算的运算符称为集合运算符. 集合运算符会除去重复的记录 ...

最新文章

  1. 扩增子三部曲:1分析图表解读大全(箱线,散点,热,曼哈顿,火山,韦恩,三元,网络)...
  2. AI志愿超强攻略|中国高校AI专业最全院校排名课程对比(附链接)
  3. 修改Moodle的日期显示改英文为中文
  4. 7.wait和waitpid
  5. aip格式转化为pdf_python提取pdf文档中的表格数据、svg格式转换为pdf
  6. Linux系统编程——I/O多路复用select、poll、epoll
  7. 数三角形(51Nod-2497)
  8. cocos2dx 3.x 快速创建项目
  9. Spring MVC 入门指南(二):@RequestMapping用法详解
  10. android中注册代码怎么写,Android P HIDL demo代码编写 (原创)
  11. 【LGR-050】洛谷8月月赛
  12. 雷观(二):当今时代最须要6项能力
  13. mysql内容_mysql 的基本内容
  14. 基于qt的贪吃蛇游戏 c语言,基于QT的贪吃蛇游戏设计
  15. bootstrap 可以拖动 表格宽度_table表格列宽可拖动
  16. 小学计算机教室培训心得,小学教师培训心得体会【通用版】
  17. 写日报、写日报,每天都要写,写工作日报到底有什么意义?
  18. 作为阿里的面试官,我有话想说。
  19. 哈罗数据分析(SQL)笔试
  20. RAC环境scan ip详解

热门文章

  1. 知识图谱学习笔记-风控知识图谱设计
  2. 用户画像-撸一部分代码啊
  3. Hierarchical Attention Networks for Document Classification 阅读笔记
  4. 卷积核个数和输入输出通道数的关系
  5. anaconda不同虚拟环境下使用jupyter的问题
  6. scipy 笔记:solve_triangular
  7. MCMC采样和M-H采样
  8. Windows下安装spark+Hadoop
  9. 【Linux】10_存储管理EXT4文件系统详解
  10. 详解如何使用Istio监控基于容器的服务