`

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

    博客分类:
  • java
 
阅读更多

原文http://www.importnew.com/16805.html

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

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

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

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

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

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

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

2. 不要相信早期的JDK APIs

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

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

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

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

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

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

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

3. 不要相信“-1”

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

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

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

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

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

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

4. 避免意外的赋值

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

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

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

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

5. 检查null和长度

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

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

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

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

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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
// 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 中 直到那该死的编译器停止工作,然后他们突然链接到了错误的方法,认为这一切都是你的错(事情总是这样)。

思考一下这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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);
    else
        good(Collections.singletonList(value));
}
 
final <T> void good(final List<T> values) {
    ...
}

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

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

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

所以说偏执是有好处的。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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是最坑爹的语句,任何喝醉了或是赌输了的人都可以在某种语言中使用它。看看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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了。因为你知道…..

分享到:
评论

相关推荐

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

    下面是我列出的的个人感觉有用而又偏执的 10 项 Java 编程技巧。请看:  1. 把字符串常量放在前面  通过把字符串常量放在比较函数equals()比较项的左侧来防止偶然的 NullPointerException 从来都不是一个坏主意...

    总结十个实用但偏执的Java编程技术

    【Java编程技术分享】本文将探讨十个在Java编程中实用且偏执的技巧,这些技巧旨在提高代码的健壮性和防止潜在的错误。在长期的编程实践中,采取这些"防御性编程"策略能够帮助开发者避免一些常见的问题。 1. **字符...

    java2年工作经验简历_java简历.doc

    在两年的工作中,开发者会遇到各种问题,通过解决这些问题,他们的编程能力、问题解决能力和团队合作技巧都会得到显著提升。此外,他们可能还接触过一些其他技术,如微服务、消息队列、缓存系统等,这些都是Java...

    java项目简历_java简历.docx

    Java 项目简历_java 简历 本资源摘要信息来自一份 Java 开发程序员的简历,涵盖了该开发程序员的个人信息、教育背景、工作经验、专业技能和项目经验等方面。 教育背景 该开发程序员毕业于新乡学院,主修计算机...

    应届生Java开发个人简历_java简历.doc

    Java开发是当今信息技术领域中最热门的编程语言之一,尤其对于应届生而言,掌握Java技能是进入IT行业的敲门砖。在个人简历中,求职者提到他系统学习了Java的基础课程,包括《C程序设计》、《C++语言程序设计》、...

    java工程师简历_java简历.docx

    - **编程语言**:熟练掌握Java编程,具备优秀的编码能力,擅长面向对象编程。 - **Web开发**:熟悉JavaWeb和JDBC,能够进行Web应用程序开发。 - **框架应用**:精通SpringMVC、Spring和MyBatis,对Struts2和...

    java工程师简历_java简历.pdf

    java工程师简历_java简历

    java工程师简历_java简历.doc

    1. 精通Java编程语言,具备扎实的基础。 2. 熟练运用Servlet、JSP和JSTL标签进行Web开发。 3. 熟悉Struts2、Hibernate、Spring、Mybatis、SpringMVC等主流Java开源框架,能够高效地进行项目开发。 4. 对Oracle和...

    java3年工作经验简历_java简历.docx

    谌纪委是一位拥有3年工作经验的Java开发工程师,他的专业技能涵盖了Java编程、开源框架的使用、前端技术以及集群解决方案。他在求职中希望找到全职的Java开发工程师职位,期望工作地点在上海,并且薪资面议。 在...

    JAVA开发经理_java个人简历模板.doc

    JAVA 开发经理个人简历模板 根据提供的简历模板,我们可以总结出以下知识点: Java EE 和 Java ME * Java EE(Enterprise Edition):用于开发大型企业级应用程序,涉及技术包括 SSH(Spring + Struts + ...

    java6年工作经验简历_java简历.docx

    Java 软件开发工程师简历 本资源是关于一名 Java 软件开发工程师的简历,总共拥有 6 年的工作经验,擅长 Java 开发、软件设计、测试和维护等技能。 Java 开发经验 * 2016.06 - 2017.02,中国民航信息网络股份有限...

    java工程师简历_应聘JAVA开发工程师.doc

    【Java工程师简历】应聘Java开发工程师的文档展示了应聘者具备扎实的Java编程基础和技术栈,以下是根据简历内容提炼出的相关知识点: 1. **Java基础**: - 面向对象编程:理解类、对象、封装、继承和多态的概念。 ...

    java2年工作经验简历_java简历.docx

    java2年工作经验简历_java简历

    java简历项目_java简历.doc

    【刘鸿羽】的个人简历显示他是一位经验丰富的JavaEE软件工程师,专长在于JAVA开发。他在【北京尚美科技责任有限公司】担任JAVA软件工程师一年,期间积累了丰富的技术和项目经验。 在【Java技能】方面,刘鸿羽拥有...

    java 简历模版_java简历.doc

    - **Java基础**:掌握扎实的Java基础知识,拥有良好的编程习惯,理解常用的设计模式。 - **前端技术**:熟悉Javascript编程,能使用jQuery和AJAX,以及EasyUI和zTree等前端插件。 - **数据库**:熟练使用MySQL和...

    Java函数式编程(十二):监控文件修改

    Java函数式编程是一种编程范式,它强调使用函数和数据流来构造程序,而不是通过显式的控制流程。在Java中,函数式编程主要体现在Java 8及其后续版本引入的Lambda表达式和Stream API上。本篇文章关注的是如何在Java中...

    java优秀工作简历_java简历.doc

    2015年8月至2017年10月,他在上海漫道科技有限公司工作,期间积累了丰富的Java开发经验,参与并完成了多个复杂项目。 总结:这位求职者具备扎实的Java基础,丰富的项目实践经验,对分布式系统、缓存、消息队列、...

Global site tag (gtag.js) - Google Analytics