当前位置: 首页 > 编程日记 > 正文

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

经过一段时间的编码(咦,我已经经历了将近20年的编程生涯,快乐的日子总是过得很快),我们开始感谢那些好习惯。因为,你知道…

“任何可能出错的事情,最后都会出错。”

这就是人们为什么喜欢进行“防错性程序设计”的原因。偏执的习惯有时很有意义,有时则不够清晰也不够聪明,也许当你想到这样写的人的时候还会觉得有点怪异。下面是我列出的的个人感觉最有用而又偏执的 10 项 Java 编程技巧。请看:

1. 把字符串常量放在前面

通过把字符串常量放在比较函数equals()比较项的左侧来防止偶然的 NullPointerException 从来都不是一个坏主意,就像这样:

// Bad
if (variable.equals("literal")) { ... }// Good
if ("literal".equals(variable)) { ... }

这是毫无疑问的,把一种表达式转换成另一种更好的表达式,并不会失去什么。只要我们的Options是真实存在的(Java 8中 Optional是对可以为空的对象进行的封装),不是吗?讨论一下…

2. 不要相信早期的JDK APIs

Java刚出现的时候,编程一定是件很痛苦的事。那时的API仍然不够成熟,你可能曾经遇到过这样一段代码:

String[] files = file.list();// Watch out
if (files != null) {for (int i = 0; i < files.length; i++) {...}
}

看起来很奇怪对吗?也许吧,但是看看这个Javadoc:

“如果抽象路径名表示的不是一个目录,那么这个方法返回null。否则返回一个字符串数组,其中每个字符串表示当前目录下的一个文件或目录。”

是的,最好再加上判空检查,以确保正确:

if (file.isDirectory()) {String[] files = file.list();// Watch outif (files != null) {for (int i = 0; i < files.length; i++) {...}}
}

糟糕!前者违反了 Java 编码中 10 个微妙的最佳实践 的规则#5和#6。因此一定要记得判 null检查!

3. 不要相信“-1”

我知道这很偏执,Javadoc中关于 String.indexOf() 的早期描述是这样的…

“字符在字符序列中第一次出现的位置将作为结果[被返回],如果字符不存在则返回-1。”

所以,-1 就可以理所当然被拿来用,对吗?我说不对,看看这个:

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

谁知道呢。也许在某个特定场合下他们将会需要另一种 编码值,如果不区分大小写的话,otherString 就会被包含进去…此时或许可以返回 -2呢?谁知道呢。

毕竟,我们有非常多关于NULL——价值亿万美金的错误的讨论。为什么不开始讨论 -1呢,某种意义上来说 -1 是 null 在int类型下的另一种形式。

4. 避免意外的赋值

是的。即使最优秀的程序员也可能犯这种错误(当然,不包括我。看#7)。

(假设这是JavaScript,我们暂且偏执地认为是这种语言)

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

再说一遍。如果你的表达式中有常量,将它放在等式左边。这样当你打算再添加一个 = 时,不容易出错。

5. 检查null和长度

不管什么时候你有一个集合、数组或者其他的,确保它存在并且不为空。

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

你不知道这些数组来自哪儿,也许是早期的JDK API呢?

6. 所有的方法都用 final 声明

你可以告诉我任何你想要的开闭原则,不过那都是胡说八道。我不相信你(可以正确继承我的类),也不相信我自己(不会意外地继承我的类)。因此除了接口(专门用于继承)都应该是严格的 final。可以查看我们的 Java 编码中 10 个微妙的最佳实践 中的#9。

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

是的,写成final。如果这样做对你来说没有意义,你也可以通过修改或重写字节码来改变类和方法,或者发送功能请求。我敢肯定重写类/方法并不是一个好主意。

7. 所有的变量和参数都用 final 声明

就像我说的。我不相信自己不会无意间重写了某个值。这么说来,我的确一点都不相信自己。因为:

image

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

// Bad
void input(String importantMessage) {String answer = "...";answer = importantMessage = "LOL accident";
}// Good
final void input(final String importantMessage) {final String answer = "...";
}

好吧,我承认,这一条我自己也不常用,虽然我应该用。我希望Java能像Scala语言一样,人们在所有地方都直接用 val 来表示变量,甚至都不考虑易变性,除非明确需要的时候他们才用 var 来声明变量,但是这样的机会特别少。

8. 重载的时候不要相信泛型

是的,这是会发生的。你觉得你写了一个超好的API,它真的是既酷炫又直观;接着就出现了一群用户,他们只是把一切类型生搬硬套进 Object 中 直到那该死的编译器停止工作,然后他们突然链接到了错误的方法,认为这一切都是你的错(事情总是这样)。

思考一下这个:

// Bad
<T> void bad(T value) {bad(Collections.singletonList(value));
}<T> void bad(List<T> values) {...
}// Good
final <T> void good(final T value) {if (value instanceof List)good((List<?>) value);elsegood(Collections.singletonList(value));
}final <T> void good(final List<T> values) {...
}

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

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

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

image

所以说偏执是有好处的。

9. 总是在switch语句里加上default

Switch…作为最滑稽的表达式之一,我不知道是该心存敬畏还是默默哭泣。不管怎样,我们既然无法摆脱 switch ,在必要的时候我们最好能够正确使用它,例如:

// Bad
switch (value) {case 1: foo(); break;case 2: bar(); break;
}// Good
switch (value) {case 1: foo(); break;case 2: bar(); break;default:throw new ThreadDeath("That'll teach them");
}

因为在当 value=3 被引入到软件中的时候,default 就能发挥作用,使其正常运行!别和我提 enum 类型,因为这对 enums 也一样适用。

10. 用大括号隔开 switch 的每一个 case 块

事实上,switch是最坑爹的语句,任何喝醉了或是赌输了的人都可以在某种语言中使用它。看看下面这个例子:

// Bad, doesn't compile
switch (value) {case 1: int j = 1; break;case 2: int j = 2; break;
}// Good
switch (value) {case 1: {final int j = 1;break;}case 2: {final int j = 2;break;}// Remember:default: throw new ThreadDeath("That'll teach them");
}

在switch语句中,为所有的case都只定义了一个作用域。事实上,这些case不是真正意义上的语句,他们更像是标签,而switch就是指向这些标签的goto语句。事实上,你甚至可以把case语句和 惊人的FORTRAN77项声明 类比,对于FORTRAN,它的神秘已经超越了它的功能。

这意味着变量final int j 可以被任何case访问,不论我们是否有break。看起来并不是很直观。我们可以通过添加简单的花括号为每一个case创建一个新的嵌套的作用域,当然不要忘了在每个 case 的语句块最后加 break。

结论

编程时的强迫症有时候看起来会很奇怪,会使得代码往往比必需的还要冗长。你可能会想,“啊,这种情况永远不会发生!”,但是正如我所说的,在经历了 20年左右的编程生涯后,你不会想要再去修正那些只是因为编程语言的古老和固有缺陷而导致的愚蠢而不必要的bug了。因为你知道…..

https://youtu.be/oO3YmT2d-8k

现在,轮到你了!

你在编程时有哪些强迫症呢?

原文链接: javacodegeeks 翻译: ImportNew.com - LynnShaw
译文链接: http://www.importnew.com/16805.html

文章转载自 开源中国社区[https://www.oschina.net]

相关文章:

如何利用SOM网络进行柴油机故障诊断

如何利用SOM网络进行柴油机故障诊断

leetcode--删除排序链表中的重复元素--python

文章目录题目题目详情示例解题代码思路代码运行结果最佳方案题目 题目详情 给定一个排序链表&#xff0c;删除所有重复的元素&#xff0c;使得每个元素只出现一次。 示例 输入: 1->1->2 输出: 1->2输入: 1->1->2->3->3 输出: 1->2->3解题代码 …

如何使用 UserAccountControl 标志操纵用户帐户属性

转载&#xff1a; http://support.microsoft.com/kb/305144 概要 在打开用户帐户的属性后&#xff0c;单击帐户选项卡&#xff0c;然后选中或清除“帐户选项”对话框中的复选框&#xff0c;则会将数值分配给 UserAccountControl 属性。分配给该属性的值通知 Windows 已启用了哪…

程序员 专属的新年祝福原来是这样的! (附中奖名单)

程序员的新年祝福会是什么样的&#xff1f;我们共收到了97位 OSCer 的回复&#xff0c;以下为支持数排名前十的祝福语&#xff1a; yale8848&#xff08;支持数&#xff1a;10&#xff09; document.write("") &#xff08;小编&#xff1a;捂脸&#xff0c;不过不知…

LSGO代码小组第16周复盘日志

LSGO代码小组第16周复盘日志&#xff0c;汇报人&#xff1a;高勇

leetcode--买股票的最佳时机II--python

文章目录题目题目详情注意示例代码思路解题代码运行结果最佳方案题目 题目详情 给定一个数组&#xff0c;它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;。…

我的广州生活~

步入11月份&#xff0c;天气逐渐转冷&#xff01;本以为广东的冬天是永远的裤头T恤&#xff0c;看来我错了。。。在凉席上抗争了一周&#xff0c;我感冒了两次&#xff0c;看来人毕竟斗不过天&#xff0c;还是乖乖的铺上褥子&#xff0c;等待南国的冬天。他们都说广州的冬天是种…

苹果手表可以运行 ruby 脚本了

不得不佩服啊&#xff01; 各位看下载地址吧https://itunes.apple.com/cn/app/ruby-2.0-for-ios-yun-xing/id727047729?mt8https://yqfile.alicdn.com/d0403806fdff7411060f9b0b059d1f9966c19447.png" >https://yqfile.alicdn.com/5dbd9a02e4252465b9896713a592e092ca…

Matlab与线性代数--广义逆矩阵

本微信图文详细介绍了Matlab中求解广义逆矩阵的方法。

leetcode--无重复字符的最长子串--python

文章目录题目题目详情示例解题代码思路代码运行结果最佳方案题目 题目详情 给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长…

TOP语句与Order By语句

默认情况下&#xff0c;如果在子查询&#xff0c;函数&#xff0c;视图中尝试去使用ORDER BY&#xff0c; CREATE VIEW dbo.VSortedOrders ASSELECT orderid, customerid FROM dbo.Orders ORDER BY orderid GO 那么可能会遇到下面的错误 消息 1033&#xff0c;级别 15&#xff…

利用“队列”解决“窗口混乱”问题

本图文利用队列这种数据结构以及多线程技术模拟了银行排队&#xff08;叫号&#xff09;软件的工作流程。

MySQL操作数据库--与MySQL零距离接触1-7

第一章 1-7操作数据库 数据库是一个集合&#xff1a;表 索引等。 MySQL语句规范&#xff1a; 关键字与函数名称全部大写 数据库名称、表名称、字段名称全部小写 SQL语句必须以分号结尾 语法结构&#xff1a; {}&#xff1a;代表必选项 …

leetcode--盛最多水的容器--python

文章目录题目题目详情说明示例解题代码思路代码运行结果最佳方案题目 题目详情 给定 n 个非负整数 a1&#xff0c;a2&#xff0c;…&#xff0c;an&#xff0c;每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线&#xff0c;垂直线 i 的两个端点分别为 (i, ai) 和 (…

创意海报生成器

今天无意中看到一个网站,用来生成一些好玩的图片. http://www.photofunia.com 转载于:https://www.cnblogs.com/victorxu/archive/2008/11/17/1334779.html

基于Go语言来理解Tensorflow

Tensorflow并非一套特定机器学习库——相反&#xff0c;其属于一套通用型计算库&#xff0c;负责利用图形表达计算过程。其核心通过C语言实现&#xff0c;同时亦绑定有多种其它语言。与Python绑定不同的是&#xff0c;Go编程语言绑定不仅允许用户在Go环境当中使用TensorFlow&am…

如何利用BP网络进行神经网络变量筛选

如何利用BP网络进行神经网络变量筛选

校园ACM--总结

文章目录题目1--字母矩阵题目详情示例解题代码思路代码运行结果题目2--二进制反转题目详情示例解题代码思路代码运行结果体会题目1–字母矩阵 题目详情 n阶字母矩阵是由n*n的英文小写字母组成的方阵&#xff0c;满足&#xff1a; 每一条副对角线上的字母相同 不同对角线上的…

阅读笔记 CCL: Cross-modal Correlation Learning with Multi-grained Fusion by Hierarchical Network

总结 CCL: Cross-modal Correlation Learning with Multi-grained Fusion by Hierarchical Network Yuxin Peng, Jinwei Qi, Xin Huang and Yuxin Yuan 常见方法 使用深度神经网络&#xff08;DNN&#xff09;的跨模态检索大体分为两个步骤&#xff1a; 1 The first learning s…

Matlab与线性代数--矩阵的LU分解

本图文详细介绍了Matlab中有关矩阵LU分解的操作。

Silverlight的企业应用

今天在Terry Lee的博客中看到《Silverlight 3 &#xff0d;瞥》&#xff0c;之后找到Scott的原文《Update on Silverlight 2 - and a glimpse of Silverlight 3》&#xff0c;发现在Scott的文章里提到了K2的Blackpoint。 Silverlight已经发布了一段时间&#xff0c;但很少听说…

leetcode--移除元素--python

文章目录题目题目详情示例说明解题代码思路代码小知识运行结果最佳方案题目 题目详情 给定一个数组 nums 和一个值 val&#xff0c;你需要原地移除所有数值等于 val 的元素&#xff0c;返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在原地修改输入数组…

翼の折れた天使たち

人は、時に強がってしまうものだ。 本当は、苦しいのに本当は、甘えたいのにでも、それを素直に表すことができない。ただ、怖いのは、自分を追い込んでしまうこと。そして、悲しいのは、後戻りができなくなること。だから、そうなる前に、自分の弱さを認めてほしい。それは、恥…

小型网站到大型网站-Mysql优化

2019独角兽企业重金招聘Python工程师标准>>> 背景 好的大型网站都是从小型网站慢慢演变来的&#xff0c;都不是一步就设计好的。现在的淘宝&#xff0c;03年创建的时候它也是只有一台服务器&#xff0c;使用的是我们目前还经常使用的lamp架构&#xff08;LinuxApach…

Matlab与线性代数--矩阵的正交分解

本图文介绍了Matlab中对于QR分解的操作。

leetcode--搜索插入位置--python

文章目录题目题目详情示例解题思路思路代码运行结果最佳方案题目 题目详情 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 示…

SQL学习笔记-嵌套查询

嵌套查询定义&#xff1a; 1 .指在一个外层查询中包含有另一个内层查询。其中外层查询称为主查询&#xff0c;内层查询称为子查询。 2 .SQL允许多层嵌套&#xff0c;由内而外地进行分析&#xff0c;子查询的结果作为主查询的查询条件 3 .子查询中一般不使用order by子句&#x…

Matlab与线性代数--矩阵的Cholesky分解

本图文介绍了Matlab对正交矩阵的Cholesky分解操作。

IIS 7启用static JSON文件能POST方法

<?xml version"1.0" encoding"UTF-8"?> <configuration> <system.webServer><handlers><add name"JSON" path"*.json" verb"GET,POST" modules"IsapiModule" scriptProcessor"…

leetcode--在排序数组中查找元素的第一个和最后一个位置--python

文章目录题目题目详情示例解题思路思路代码运行结果最佳方案题目 题目详情 给定一个按照升序排列的整数数组 nums&#xff0c;和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 你的算法时间复杂度必须是 O(log n) 级别。 如果数组中不存在目标值&#…