java effective 注解
Death_Huimie
这个作者很懒,什么都没留下…
展开
-
第七十六条 保护性编写readObject方法
书中本条目开头给了一个代码例子。public final class Period implements Serializable { private final Date start; private final Date end; public Period(Date start, Date end) { this.start = new ...原创 2018-12-25 12:48:35 · 576 阅读 · 0 评论 -
第五十六条 遵守普遍接受的命名惯例
java 发展了几十年了,已经有了一套自己的命名规范和惯例了,下面整理了一下,设计字面和语法,我们需要遵守这些惯例,一旦违反,不一定会出错,但维护起来或者其他人可读性就大大降低了,并给其他人造成一定困扰。 包: 包名一般用 . 符号隔开,一般都是小写,并且以公司的顶级域名作为开头; java javax 等属于例外,我们不要模仿;包的命名尽量简短,不要拖拉过长。类和接口: 首字母要大...原创 2018-11-02 15:08:27 · 352 阅读 · 0 评论 -
第五十八条 对可恢复的情况使用受检异常,对编程错误使用运行时异常
对于异常,我们知道,基类为 Throwable,它有两个子类,Exception 和 Error,Exception 通常被称为异常, Error被称为错误。Exception异常又分为两种,一种是受检异常(checkedexception) ,另一种是运行时异常(runtime exception) 。在决定使用受检异常或运行异常时,主要原则: 如果期望调用者能够是当地恢复,对于这种情况就应该...原创 2018-11-06 11:29:41 · 822 阅读 · 0 评论 -
第五十五条 谨慎地进行优化
开篇就提出了三个名人的观点,概括下来,就是不要进行优化,不成熟的优化往往会惹出大问题。我们写程序,往往喜欢优化,但不正确的优化,产生的结果可能既不快速,也不 正确,而且还不容易修正。不要为了性能去牺牲合理的结构,我们应该努力写好的程序而不是快的程序,但这并不意味着可以放弃性能,而是好的架构可以提升性能和扩展功能,如果一味追求性能,牺牲了框架,后期的扩展和性能提升往往会遇到瓶颈,并且牵一发而动全...原创 2018-11-01 16:15:58 · 291 阅读 · 0 评论 -
第五十三条 接口优先于反射机制
反射中的核心机制是 java.lang.reflect 这个包,里面提供了 通过程序来访问关于已装载的类的信息 的能力,通过一个Class实例,就可以获取Constructor、Method、Field实例,获得构造方法、方法、成员变量等属性。java用法,一般是创建对象,然后调用方法;反射是根据class或类名,创建对象,调用方法。两者有颠倒的意味。反射机制允许一个类调用另外一个类,即使对方还没...原创 2018-10-30 14:48:13 · 201 阅读 · 0 评论 -
第四十九条 基本类型优先于装箱基本类型
Java系统数据方面,分两种类型,一种是八大基本类型,包括 int long short 等,另一种是对象引用类型,如 String List 自定义的对象等等。八大基本类型都有一个对应的引用类型,称为装箱基本类型,例如 int double boolean 对应的装箱类型是 Interger Double Boolean。 Java 1.5 版本后,增加了自动装箱和自动拆箱功能,比如List里不...原创 2018-10-24 19:55:26 · 205 阅读 · 0 评论 -
第五十四条 谨慎地使用本地方法
本地方法一般是指由c或c++写的特殊方法,通过JNI调用,并返回到java程序语言。本地方法一般是为了高效,或者是因为java语言实现不了一些功能,所以才用到它。现在,java平台越来越成熟,提供了大量之前没有的方法和特性,同时也优化了性能,以前只有本地方法才能实现的,现在直接使用java语言也能实现了,并且一些以前效率低下的功能,现在也都提高了,所以还是优先使用java功能。使用本地方法提...原创 2018-10-31 14:35:23 · 269 阅读 · 0 评论 -
第五十二条 通过接口引用对象
对于参数类型,要优先使用接口而不是类,如果有合适的接口类型,那么参数、返回值、变量和域等,应该使用接口来声明,当创建实体对象时,再用具体的对象,有点类似于多态的使用。比如说在使用Vector的情形,它是List接口的一个实现类,我们在声明变量时,应该 List<String> list = new Vector<>();而不是直接使用Vector 来创建对象...原创 2018-10-29 15:26:44 · 255 阅读 · 0 评论 -
第四十八条 如果需要精确的答案,请避免使用float和double
float和double主要为了科学计算和工程计算而设计,执行二进制浮点运算,为了在广泛的数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不适合用于需要精确结果的场合,尤其是货币计算。因为两位小数的话,相减,很可能就会出现问题,例如有1.03元,花出去0.42元, System.out.println(1.03 - .42); 结果为...原创 2018-10-23 16:30:35 · 253 阅读 · 0 评论 -
第五十一条 当心字符串连接的性能
字符串的串联,就是用 + 把多个字符串拼接成一个字符串的便利途径。链接 n 个字符串为一个,这种用法很方便,但不一定都可取。例如,大量的串联字符串,很可能会造成性能的下降 public String statement(){ String result = ""; for(int i = 0, count = numItem(); i < count...原创 2018-10-28 10:55:21 · 170 阅读 · 0 评论 -
第五十条 如果其他类型更适合,则尽量避免使用字符串
字符串用来表示文本,字符串在各个系统中通用,并且java对它支持很好,所以,给人个错觉,各个场合都能使用字符串,我们公司项目里就有这个问题,不管是 int long boolean 都转换为字符串来判断,本条目列举一些不适合字符串的情景。一、字符串不适合代替其他的值类型。当数据从网络或文件或键盘进入程序后,通常是以字符串的形式传进来,但不代表我们接收使用时也一定要是字符串,如果是文本信息,则...原创 2018-10-28 10:40:34 · 314 阅读 · 0 评论 -
第四十五条 将局部变量的作用域最小化
本条目与十三条 使类和成员的可访问性最小化 本质上是一样的,将局部变量的作用域最小化,也就是说在第一次使用的地方再定义局部变量,这样可以增强代码的可读性和维护性,降低出错的可能。Java 语言允许在任何地方声明变量,但如果变量提前声明,一方面容易造成误读,分散读者的注意力,会让读者误以为这个变量马山要被用到,结果往下面看了n行才用到,如果隔了n个n行,读者可能已经忘了这个变量在哪个地方定义的,作用...原创 2018-10-17 09:28:31 · 243 阅读 · 0 评论 -
第三十二条 用EnumSet代替位域
在java中,我们经常会定义一些常量值,来表示一些状态,每个常量值代表的意思都不一样,有的还是可以共存的public class Text { public static final byte STYLE_BOLD = 1<<0; // 1 public static final byte STYLE_ITALIC = 1<&...原创 2018-09-30 17:08:35 · 411 阅读 · 0 评论 -
第三十一条 用实例域代替序数
枚举中有个方法, ordinal()方法,它的值是枚举常量在类型中的数字位置,如果把枚举里面的内容对象看成是一个数组,那么,这个值就是索引。public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public int numberOfMus...原创 2018-09-30 15:34:35 · 291 阅读 · 0 评论 -
第三十条 用enum代替int常量
枚举类型是指一组固定常量组成合法值的类型,例如一年四季、太阳系行星、一副牌的四种花色等可以归纳的东西。在枚举出现之前,一般都是用常量来标识每个不同的类型public static final int APPLE_FUJI = 0;public static final int APPLE_PIPPIN = 1;public static final int APPLE_GRANNY_SM...原创 2018-09-30 13:49:10 · 336 阅读 · 0 评论 -
第四十七条 了解和使用类库
如果我们需要取一个介于0与n之间的随机数,如果我们自己写的话,借助Random工具,可以 private final static Random mRandom = new Random(); static int random(int n){ return Math.abs(mRandom.nextInt()) % n; }测试一下,看看方法获取随...原创 2018-10-18 19:17:36 · 208 阅读 · 0 评论 -
第四十条 谨慎设计方法签名
本条目是若干API的设计技巧总结,是总结性文字。一、谨慎地选择方法的名称。这个我们应该遵循命名模式的规范,比如驼峰命名,言简意赅,不要词不达意,应该与包名的风格一样,同时大众化的,不要选择生僻的单词,也不要使用拼音,更多的命名规范后面会细讲; 二、不要过于追求提供便利的方法。方法应尽其所能,方法太多的话,会把人绕晕,需要花费大量时间学习和维护,要尽量简化; 三、避免过长的参数列表。一个方法...原创 2018-10-08 19:49:47 · 237 阅读 · 0 评论 -
第四十四条 为所有导出的API元素编写文档注释
如题,想让api可用,我们需要为它编写文档,传统的API文档是手动生成的,所以保存文档与代码同步比较费力,java 环境提供了 javadoc 的工具,可以为我们生成文档,根据我们写的方法的注释,自动生成对应的文档。 如果使用的是 eclipse, 可以百度一下,网上资料成群; 如果是用 dos 命令, 输入 javadoc -d myhelp -author -version name.java...原创 2018-10-15 13:38:04 · 273 阅读 · 0 评论 -
第五十九条 避免不必要地使用受检的异常
受检的异常是java程序的一个很好的特性,使用它可以大大提高代码的可靠性,但如果大量使用异常,则会给代码的结构带来不方便,如果声明了大量的异常,都需要在抛出异常的地方添加相对应的处理代码,这会给开发者带来很大的负担。异常这个东西,不能过分依赖。就像药一样,药能治病,但是医药三分毒。健康的一个人,可以通过穿衣服保暖,就决不要去吃药维持体温。我们使用异常时,需要满足以下条件,一、正确的使用了ap...原创 2018-11-07 21:45:21 · 327 阅读 · 0 评论 -
第五十七条 只针对异常的情况才使用异常
异常,是java中不可绕过的一部分。善用异常,可以大大提高效率。但如果有一天,一不小心,遇到下面的代码 try { int i = 0; while (true){ range[i++].climb(); } }catch (ArrayIndexOutOfBou...原创 2018-11-05 20:49:59 · 442 阅读 · 0 评论 -
第六十一条 抛出与抽象相对应的异常
异常,也有一套自己的体系,尤其是java的一大特征是封装,所以对应的,如果封装的方法中抛出的异常与它执行的任务没什么明显的关系,则很容易令人不知所措,给人以驴唇不对马嘴,尤其是方法是由底层抽象方法抛出的异常,更容易发生这种情况,不但编码规范错误,更可能污染高层的api,这样就可能破坏客户端的架构,为了避免这个问题,更高层的实现应该捕获底层的异常,同时向上抛出可以让更高层抽象解释的异常,这种做法叫做...原创 2018-11-13 17:51:03 · 1372 阅读 · 0 评论 -
第七十五条 考虑使用自定义的序列化形式
序列化使用起来比价方便,但有一些常见的细节需要注意,比如说定义 serialVersionUID 值,关键字 transient 的用法,下面就用例子来说明定义一个bean,实现序列化的接口,public class Student implements Serializable { int age; String address; public Student...原创 2018-12-24 14:42:44 · 260 阅读 · 0 评论 -
第七十八条 虑用序列化代理代理序列化实例
实现了序列化的类,在序列化和反序列化时,由 writeObject 方法把对象写入磁盘,实例的创建是由readObject方法来完成的,因此,每次反序列化出来的对象的地址值都不一样,为了解决这个问题,可以编写 readResolve() 方法,或者用枚举代替实例类。有没有其他的办法呢?我们知道,执行 readObject 时,外部可能会通过伪字节流和内部盗用域来攻击程序,它就是伪造一个字节流,通...原创 2018-12-29 11:27:01 · 249 阅读 · 0 评论 -
第七十七条 对于实例控制,枚举类型优于readResolve
我们应该知道一点, readResolve() 方法,会在 readObject() 之后被调用,readResolve() 的返回值将会代替 readObject() 中反序列化的对象, readObject() 中反序列化的对象会被丢弃。我们知道,readObject() 会单独开启一个构造器,会打破一些东西。例如单利 public final class MySingleton ...原创 2018-12-28 16:13:36 · 257 阅读 · 0 评论 -
第七十二条 不要依赖于线程调度器
当有多个线程可以运行时,由线程调度器决定哪些线程将会运行,以及运行多长时间。任何一个合理的操作系统在做出这样的决定时,都会努力做到公正,但是所采用的策略却相差无几。因此,编写良好的程序不应该依赖于这种策略的细节。任何依赖于线程调度器来达到正确性或者性能要求的程序,很有可能都是不可移植的。我们一般是需要把功能单独模块化,保持独立,超级解耦,随时都能被拎出来,被其他项目复用。要编写健壮的、响应良好...原创 2018-12-10 20:56:53 · 443 阅读 · 0 评论 -
第七十四条 谨慎地实现 serizable 接口
我们把 String 或 八大基本类型的值保存在内存,或保存到本地file文件夹里,或通过网络传给服务端,比较容易;但我们自定义的 class 对象怎么办,他们直接保存到本地,保存不了他们的属性的值,比如 class Student 对象,里面 age 和 address 两个属性;有个对象 student,age 为 13,address 为 北京,我们想把student 的值直接保存到数据库...原创 2018-12-20 21:38:16 · 633 阅读 · 0 评论 -
第七十三条 避免使用线程组
除了线程、锁、监视器外,系统还提供了一个基本的抽象,即线程组。线程组的目的是作为一种隔离的机制,但实际上却没达到这个目的。因为线程组 ThreadGroup 表示一组线程的集合,一旦这个线程归属到一个线程组之中后,这个线程就不能再更换其所在的线程组。这种就是把一条线程卡死在一个线程组中了,并非是隔离。但线程组有个好处:线程组可以进行复制,统一进行异常处理设置等。但是从线程安全性的角度来看,Thre...原创 2018-12-15 14:07:45 · 379 阅读 · 1 评论 -
第七十一条 慎用延迟初始化
延迟初始化是延迟到需要域的值时才将它初始化的这种行为。如果永远不需要这个值,那么这个域就永远不会被初始化,这种方法既适用于静态域,也适用于实例域。延迟初始化主要是一种优化方式。就像大多数的优化一样,对于延迟初始化,最好建议“除非绝对必要,否则就不要这么做”。延迟初始化就像一把双刃剑。它降低了初始化类或者创建实例的开销,却增加了访问被延迟初始化的域的开销。根据延迟初始化的域最终需要初始化的比例、...原创 2018-12-07 11:50:37 · 416 阅读 · 0 评论 -
第六十九条 并发工具优先于wait和notify
java中经常会用到子线程等,当各个线程作操作后,需要处理数据,我们需要自己重写wait和notify方法,但1.5以后,java平台对这些要求提高了,我们可以用高级的工具来代替。比如用线程池管理线程,或者java提供的并发集合类以及同步器(Synchronizer)。线程池上一条介绍过了。并发集合Concurrent Collection,它的标准接口如 List Queue Map等,为了提供...原创 2018-12-03 17:02:17 · 317 阅读 · 0 评论 -
第七十条 线程安全性的文档化
当一个类的方法或静态方法被并发使用的时候,很可能会造成线程安全隐患。如果你没有在一个类的文档中描述其行为的并发性情况,使用这个类的其他人将不得不做出某些demo来验证它是否并发安全,可能缺少足够的同步,或者过度同步,无论属于这其中的哪种情况,都可能会发生严重的错误。我们可能听过这样的说法:通过查看文档中是否出现synchronized修饰符,可以确定一个方法是否是线程安全的。这种说法是错误的,在正...原创 2018-12-05 16:13:06 · 795 阅读 · 0 评论 -
第六十七条 避免过度同步
上一条,我们知道了并发中要对数据进行安全性保护,防止数据出错,一般是进行同步保护,但做事情不能从一个极端走向另外一个极端,在同步保护的同时,要注意防止过度同步,因为它会导致性能下降、死锁,甚至是其他的一些不确定行为。本条目中的一个醒目观点就是,如果一个方法被同步了,那么,这个同步方法里涉及的有其他方法,那么这些方法不应该是回调,或者可以被重写。举个例子,我们在 16 条中举例个 Forwardin...原创 2018-11-28 10:53:50 · 276 阅读 · 0 评论 -
第六十八条 executor和task优先于线程
java比较早的时候,就提供了 WorkQueue WorkQueueImpl 这些类,它允许客户端将后台的异步线程加入这个队列,当不在需要这个工作队列时,客户端端可以调用一个方法,让后台线程完成了在队列中的工作后,终止自己。我们自己在用这个功能时,需要特别小心注意,防止出错。java 1.5 以后,java 平台中增加了 java.util.concurrent,这个包中包含了Executor ...原创 2018-11-30 10:51:40 · 255 阅读 · 0 评论 -
第六十三条 在细节消息中包含能捕获失败的信息
程序为了捕获异常,如果失败了,系统会自动打印该异常的信息,在堆栈中包含该异常的字符串表示法,即它的toString方法的调用结果,包含了一系列信息:该异常的类名和细节消息。基本上,这是程序员在调查程序失败原因的必要的信息。如果这个失败不易重现,这失败的信息就异常重要,因此,异常类型的toString方法应该尽可能多地返回有关失败原因的信息,这些属于log日志的范畴,是需要好好分析的,为了更好的搭...原创 2018-11-19 14:30:42 · 234 阅读 · 0 评论 -
第六十六条 同步访问共享的可变数据
平时开发中,单线程的逻辑一般都好控制,但是并发情况下,多线程同时操作一个数据,可控性的难度就增加了,因为并发的情况不确定,并且除了问题也不好复现。因此,并发是一个重点,也是一个难点,并发中对数据的控制操作,就成为了并发的重点。同步关键字 synchronized ,可以保证同一时刻,只有一个线程可以执行某个方法。同步是为了线程安全,对此,需要满足两个特性,原子性和可见性。 同步的意思是,当一个对象...原创 2018-11-23 16:30:06 · 205 阅读 · 0 评论 -
第六十五条 不要忽略异常
不要忽略异常,这条建议看上去很容易,但我们代码中却常常能看到反例。当api的设计中声明某些方法中会抛出某个异常时,它们往往在说明一些情况,某些场景下可能会发生异常,所以,我们不应该忽略它。忽略异常的方法很简单,只要用个 try...catch 把它包裹起来就行了,并且 catch 里面什么都不写。一旦这样操作了,我们没有针对异常情况做对应的逻辑处理,只是简单的把它给忽略了,代码是不会崩溃了,但可能...原创 2018-11-21 14:43:39 · 551 阅读 · 0 评论 -
第六十四条 努力使失败保持原子性
当对象抛出异常后,我们希望这个对象的数据能保持抛出异常之前的状态,比如对象里面有个age的属性,之前值为20,这时候对象抛出了异常,我们希望异常后,这个对象的age值仍为20,而不是直接变为0。尤其是受检的异常,我们总是期望程序能尽量完美的运行下去,从异常中恢复后,保证数据不改变,不丢失。程序对象遇到了异常,但对象的属性值不应该改变,仍保持调用前的状态和值。具有这种属性的方法被称为具有失败原子性。...原创 2018-11-20 18:01:51 · 571 阅读 · 0 评论 -
第六十二条 每个方法抛出的异常都要有文档
每个方法,都要有文档注释,这样便于后期自己回顾当初的功能以及便于他人的阅读理解,同样的,每个方法抛出的异常,也需要文档注释。因此,花费时间为每个方法抛出的异常文档是特别重要的。我们要记住,需要声明受检的异常,用Javadoc的@throws标记,并记录每个异常的条件。如果一个方法会抛出多个异常类,不要直接声明可以抛出这些类的父类,也不要声明一个方法 “throws Exception”,或者直接声...原创 2018-11-14 13:47:55 · 317 阅读 · 0 评论 -
第六十条 优先使用标准的异常
通俗来说,高手和菜鸟一个比较明显的区别,就是关于代码的复用,高手可以高度的重用,异常也不例外。java平台提供了一系列基本的未受检的异常,满足了绝大多数API的异常抛出需求。重用现有异常有很多好处,因为Java提供的异常是公共的,大家都在使用,其他人也熟悉,所以使你的api更容易学习和使用;异常的api大家都熟悉,所以代码的可读性会跟好,大家都熟悉这些异常;异常类越少,内存开销也越小,开销也越小。...原创 2018-11-12 16:33:04 · 265 阅读 · 0 评论 -
第三十九条 必要时进行保护性拷贝
Java语言是一种比较省力的语言,它对于缓冲区溢出、数组越界、非法指针等都自动免疫,有垃圾自动回收机制等等,比C、C++要安全的多。即使是安全的语言,也有自己的独特机制,也是需要把一些东西进行隔离。我们知道,Java 语言中有八大基本类型和对象类型,基本类型是多少就是多少,没有引用,但对象类型是有个地址值的,存在于堆栈之中,就是这个地址值,可能会随时改变,所以,我们需要对于这种情况做一些防护。看例...原创 2018-10-08 15:40:14 · 257 阅读 · 0 评论 -
第三十八条 检查参数的有效性
绝大多数的方法和构造器,都需要传递给它们参数,并且对参数都有一定的限制,比如:数组和集合的索引必须是非负数,对象引用不能为null,类型转换时必须一致等,这些是常见的。对于这些,我们应当在文档中标明,需要在方法开头处检查参数,意思就是在可能刚出现错误的苗头时,就检查出错误,这是一个普遍的原则问题,如果不能在错误发生时马上检查出错误,那么就有点麻烦了,可能等我们一行一行的去找错误,需要耗费大量的时...原创 2018-10-08 11:05:59 · 546 阅读 · 0 评论