java最小访问原则_Android基础进阶之EffectiveJava翻译系列(第七章:通用原则)
本章主要讨论语言的具体内容。它讨论了局部变量的处理、控制结构、库的使用、各种数据类型的使用,以及使用反射和本地方法。最后,讨论了优化和命名约定
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翻译系列(第七章:通用原则)相关推荐
- java程序设计基础_陈国君版第五版_第七章例题
java程序设计基础_陈国君版第五版_第七章例题 class Cylinder {private double radius;private int height;private double pi ...
- java adt入门教程_Android基础入门教程目录
第一章:环境搭建与开发相关(已完结 10/10) https://blog.csdn.net/coder_pig/article/details/50000773 Android基础入门教程--1.1 ...
- 安卓的java无法访问网络_Android网络访问的基本方法
Android访问网络的两种主要方式: 1.标准Java接口(java.net) ----HttpURLConnection,可以实现简单的基于URL请求.响应功能: 2.Apache接口(org.a ...
- java override 访问权限_java基础之——访问修饰符(private/default/protected/public)
1. 访问修饰符介绍 java中的访问修饰符包含了四种:private.default(没有对应的保留字).protected和public.它们的含义如下:private:如果一个元素声明为priv ...
- 最新java初级高级,python基础进阶,机器学习视频资料
我是在校口碑,现在整理了一些编程,java,python,框架,大数据资料,适用于小白和大牛!! 转载于:https://blog.51cto.com/13135855/2342878
- java基础实战练习_JAVA入门第三季第七章实战练习
首先,先创建一个Gammer类与一个Poker类. /* * Gammer类包含int类型的id属性与String类型的name属性! * id用int类型是为了测试后面创建用户时输入异常的情况. * ...
- java狗具有特别的接飞盘的方法_java第七章 多态 课堂笔记/作业
什么是多态: 用同一个引用类型,使用不同的实例,得到不同的结果 实现对台的三个要素是: 继承.方法重写.父类引用指向子类对象 1.使用多态时:是使用父类的类型,但是对象还是子类的对象 2.如果子类不重 ...
- 零基础学前端开发技术之第七章 浮动塌陷
知识点: 1.浮动塌陷的概念 2.浮动塌陷的解决 1:浮动塌陷的概念 <!DOCTYPE html> <html><head><meta charset=&q ...
- MICK-SQL基础教程(第二版)第七章 集合运算
第七章 集合运算 表的加减法 通过集合运算,可以得到两张表中记录的集合或者公共记录的集合,又或者其中 某张表中的记录的集合.像这样用来进行集合运算的运算符称为集合运算符. 集合运算符会除去重复的记录 ...
最新文章
- 扩增子三部曲:1分析图表解读大全(箱线,散点,热,曼哈顿,火山,韦恩,三元,网络)...
- AI志愿超强攻略|中国高校AI专业最全院校排名课程对比(附链接)
- 修改Moodle的日期显示改英文为中文
- 7.wait和waitpid
- aip格式转化为pdf_python提取pdf文档中的表格数据、svg格式转换为pdf
- Linux系统编程——I/O多路复用select、poll、epoll
- 数三角形(51Nod-2497)
- cocos2dx 3.x 快速创建项目
- Spring MVC 入门指南(二):@RequestMapping用法详解
- android中注册代码怎么写,Android P HIDL demo代码编写 (原创)
- 【LGR-050】洛谷8月月赛
- 雷观(二):当今时代最须要6项能力
- mysql内容_mysql 的基本内容
- 基于qt的贪吃蛇游戏 c语言,基于QT的贪吃蛇游戏设计
- bootstrap 可以拖动 表格宽度_table表格列宽可拖动
- 小学计算机教室培训心得,小学教师培训心得体会【通用版】
- 写日报、写日报,每天都要写,写工作日报到底有什么意义?
- 作为阿里的面试官,我有话想说。
- 哈罗数据分析(SQL)笔试
- RAC环境scan ip详解