偏执却管用的10条Java编程技巧

经过一段时间的编码(咦,我已经经历了将近20年的编程生涯,快乐的日子总是过得很快),我们开始感谢那些好习惯。因为,你知道… “任何可能出错的事情,最后都会出错。” 这就是人们为什么喜欢进行“防错性程序设计”的原因。偏执的习惯有时很有意义,有时则不够清晰也不够聪明,也许当你想到这样写的人的时候还会觉得有点怪异。下面是我列出的的个人感觉最有用而又偏执的 10 项 Java 编程技巧。请看: 1.把字符串常量放在前面 通过把字符串常量放在比较函数equals()比较项的左侧来防止偶然的 NullPointerException 从来都不是一个坏主意,就像这样:

Java代码

  1. // Bad
  2. if (variable.equals("literal")) { ... }
  3. // Good
  4. if ("literal".equals(variable)) { ... }

这是毫无疑问的,把一种表达式转换成另一种更好的表达式,并不会失去什么。只要我们的Options是真实存在的(Java 8中 Optional是对可以为空的对象进行的封装),不是吗?讨论一下… 2.不要相信早期的JDK APIs Java刚出现的时候,编程一定是件很痛苦的事。那时的API仍然不够成熟,你可能曾经遇到过这样一段代码:

Java代码

  1. String[] files = file.list();
  2. // Watch out
  3. if (files != null) {
  4. for (int i = 0; i < files.length; i++) {
  5. ...
  6. }
  7. }

看起来很奇怪对吗?也许吧,但是看看这个Javadoc: “如果抽象路径名表示的不是一个目录,那么这个方法返回null。否则返回一个字符串数组,其中每个字符串表示当前目录下的一个文件或目录。” 是的,最好再加上判空检查,以确保正确:

Java代码

  1. if (file.isDirectory()) {
  2. String[] files = file.list();
  3. // Watch out
  4. if (files != null) {
  5. for (int i = 0; i < files.length; i++) {
  6. ...
  7. }
  8. }
  9. }

糟糕!前者违反了Java编码中10个微妙的最佳实践的规则#5和#6。因此一定要记得判 null检查! 3. 不要相信“-1” 我知道这很偏执,Javadoc中关于 String.indexOf() 的早期描述是这样的… “字符在字符序列中第一次出现的位置将作为结果[被返回],如果字符不存在则返回-1。” 所以,-1 就可以理所当然被拿来用,对吗?我说不对,看看这个:

Java代码

  1. // Bad
  2. if (string.indexOf(character) != -1) { ... }
  3. // Good
  4. if (string.indexOf(character) >= 0) { ... }

谁知道呢。也许在某个特定场合下他们将会需要另一种 编码值,如果不区分大小写的话,otherString 就会被包含进去…此时或许可以返回 -2呢?谁知道呢。 毕竟,我们有非常多关于NULL——价值亿万美金的错误的讨论。为什么不开始讨论 -1呢,某种意义上来说 -1 是 null 在int类型下的另一种形式。 4.避免意外的赋值 是的。即使最优秀的程序员也可能犯这种错误(当然,不包括我。看#7)。 (假设这是JavaScript,我们暂且偏执地认为是这种语言)

Java代码

  1. // Ooops
  2. if (variable = 5) { ... }
  3. // Better (because causes an error)
  4. if (5 = variable) { ... }
  5. // Intent (remember. Paranoid JavaScript: ===)
  6. if (5 === variable) { ... }

再说一遍。如果你的表达式中有常量,将它放在等式左边。这样当你打算再添加一个 = 时,不容易出错。 5.检查null和长度 不管什么时候你有一个集合、数组或者其他的,确保它存在并且不为空。

Java代码

  1. // Bad
  2. if (array.length > 0) { ... }
  3. // Good
  4. if (array != null && array.length > 0) { ... }

你不知道这些数组来自哪儿,也许是早期的JDK API呢? 6.所有的方法都用 final 声明 你可以告诉我任何你想要的开闭原则,不过那都是胡说八道。我不相信你(可以正确继承我的类),也不相信我自己(不会意外地继承我的类)。因此除了接口(专门用于继承)都应该是严格的 final。可以查看我们的Java编码中10个微妙的最佳实践中的#9。

Java代码

  1. // Bad
  2. public void boom() { ... }
  3. // Good. Don't touch.
  4. public final void dontTouch() { ... }

是的,写成final。如果这样做对你来说没有意义,你也可以通过修改或重写字节码来改变类和方法,或者发送功能请求。我敢肯定重写类/方法并不是一个好主意。 7.所有的变量和参数都用final声明 就像我说的。我不相信自己不会无意间重写了某个值。这么说来,我的确一点都不相信自己。因为:

这也是为什么所有的变量和参数都用final声明的原因。

Java代码

  1. // Bad
  2. void input(String importantMessage) {
  3. String answer = "...";
  4. answer = importantMessage = "LOL accident";
  5. }
  6. // Good
  7. final void input(final String importantMessage) {
  8. final String answer = "...";
  9. }

好吧,我承认,这一条我自己也不常用,虽然我应该用。我希望Java能像Scala语言一样,人们在所有地方都直接用 val 来表示变量,甚至都不考虑易变性,除非明确需要的时候他们才用 var 来声明变量,但是这样的机会特别少。 8.重载的时候不要相信泛型 是的,这是会发生的。你觉得你写了一个超好的API,它真的是既酷炫又直观;接着就出现了一群用户,他们只是把一切类型生搬硬套进 Object 中 直到那该死的编译器停止工作,然后他们突然链接到了错误的方法,认为这一切都是你的错(事情总是这样)。 思考一下这个:

Java代码

  1. // Bad
  2. <T> void bad(T value) {
  3. bad(Collections.singletonList(value));
  4. }
  5. <T> void bad(List<T> values) {
  6. ...
  7. }
  8. // Good
  9. final <T> void good(final T value) {
  10. if (value instanceof List)
  11. good((List<?>) value);
  12. else
  13. good(Collections.singletonList(value));
  14. }
  15. final <T> void good(final List<T> values) {
  16. ...
  17. }

因为,你知道的…你的用户们,他们就像这样

Java代码

  1. // This library sucks
  2. @SuppressWarnings("all")
  3. Object t = (Object) (List) Arrays.asList("abc");
  4. bad(t);

相信我,我看过的多了,还有这样的

所以说偏执是有好处的。 9.总是在switch语句里加上default Switch…作为最滑稽的表达式之一,我不知道是该心存敬畏还是默默哭泣。不管怎样,我们既然无法摆脱 switch ,在必要的时候我们最好能够正确使用它,例如:

Java代码

  1. // Bad
  2. switch (value) {
  3. case 1: foo(); break;
  4. case 2: bar(); break;
  5. }
  6. // Good
  7. switch (value) {
  8. case 1: foo(); break;
  9. case 2: bar(); break;
  10. default:
  11. throw new ThreadDeath("That'll teach them");
  12. }

因为在当 value=3 被引入到软件中的时候,default 就能发挥作用,使其正常运行!别和我提 enum 类型,因为这对 enums 也一样适用。 10.用大括号隔开switch的每一个case块 事实上,switch是最坑爹的语句,任何喝醉了或是赌输了的人都可以在某种语言中使用它。看看下面这个例子:

Java代码

  1. // Bad, doesn't compile
  2. switch (value) {
  3. case 1: int j = 1; break;
  4. case 2: int j = 2; break;
  5. }
  6. // Good
  7. switch (value) {
  8. case 1: {
  9. final int j = 1;
  10. break;
  11. }
  12. case 2: {
  13. final int j = 2;
  14. break;
  15. }
  16. // Remember:
  17. default:
  18. throw new ThreadDeath("That'll teach them");
  19. }

在switch语句中,为所有的case都只定义了一个作用域。事实上,这些case不是真正意义上的语句,他们更像是标签,而switch就是指向这些标签的goto语句。事实上,你甚至可以把case语句和惊人的FORTRAN77项声明类比,对于FORTRAN,它的神秘已经超越了它的功能。 这意味着变量final int j 可以被任何case访问,不论我们是否有break。看起来并不是很直观。我们可以通过添加简单的花括号为每一个case创建一个新的嵌套的作用域,当然不要忘了在每个 case 的语句块最后加 break。 结论 编程时的强迫症有时候看起来会很奇怪,会使得代码往往比必需的还要冗长。你可能会想,“啊,这种情况永远不会发生!”,但是正如我所说的,在经历了20年左右的编程生涯后,你不会想要再去修正那些只是因为编程语言的古老和固有缺陷而导致的愚蠢而不必要的bug了。因为你知道….. https://youtu.be/oO3YmT2d-8k 现在,轮到你了! 你在编程时有哪些强迫症呢?

原文发布于微信公众号 - 我是攻城师(woshigcs)

原文发表时间:2015-10-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏HansBug's Lab

算法模板——Trie树

实现功能——实现对于不同字符串以及之前出现过的字符串的识别,对于单个长度为L的字符串,复杂度为O(L); 代码不难懂,直接上(在识别字符串方面,个人觉得其好处远...

2055
来自专栏c#开发者

深入abstract class和interface

abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。...

3589
来自专栏Java技术栈

国外大神总结的 10 个 Java 编程技巧!

2912
来自专栏IT 指南者专栏

Java 数据结构与算法系列之冒泡排序

相信大部分同学都已经学过数据结构与算法这门课了,并且我们可能都会发现一个现象就是我们所学过的数据结构与算法类的书籍基本都是使用 C 语言来写的,好像没见过使用 ...

1566
来自专栏Aloys的开发之路

基于对象和面向对象的区别

基本上每个程序员都听过面向对象(Object-oriented)和基于对象(Object-based)这两个概念。其实这两个概念并没有很明显的界线,不过现在业界...

2009
来自专栏企鹅号快讯

面向对象的初步理解连载 7

面向对象是一种主流的编程思维,其核心是把现实世界中的对象,对象之间的关系模拟到程序世界中,构造一个软件系统。 Java 是一种典型的面向对象编程语言。这篇文章主...

2049
来自专栏机器学习算法工程师

面试题——股票利益最大化

1. 题目 ...

3456
来自专栏数据结构与算法

1014. 写评语

1014. 写评语 (Standard IO) 时间限制: 1000 ms  空间限制: 262144 KB  具体限制  题目描述 输入某学生成绩score...

3934
来自专栏desperate633

LeetCode 121. Best Time to Buy and Sell Stock题目Solution

假设有一个数组,它的第i个元素是一支给定的股票在第i天的价格。如果你最多只允许完成一次交易(例如,一次买卖股票),设计一个算法来找出最大利润。 样例 给出一...

783
来自专栏怀英的自我修炼

怀英漫谈2-JS语法初涉

今天碰了一下JS的语法,想与你聊聊这个。这篇文章适合前端设计师,不过在文末,我也为你准备了一些感悟,有兴趣的不妨跳到最后一看。 总体来看,JS的语法和Java的...

37810

扫码关注云+社区

领取腾讯云代金券