十大有用但又偏执的Java编程技术

经过一段时间的编码(以我为例,大约20年左右,当您玩得开心时光飞逝),人们开始接受这些习惯。 因为,你知道...

任何可能出错的事情都会发生。

这就是为什么人们会采用“防御性编程”的原因,即偏执狂的习惯有时会变得很有意义,有时会变得晦涩难懂和/或聪明,甚至在想到编写者时也会有些怪异。 这是我个人列出的十大有用但又偏执的Java编程技术。 我们走吧:

1.首先将字符串文字

通过将String文字放在equals()比较的左侧,来防止偶发的NullPointerException从来不是一个坏主意,如下所示:

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

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

这很容易。 将表述从不太好的版本改写为更好的版本并不会丢失任何内容。 如果我们只有真正的期权 ,对吗? 不同的讨论…

2.不要相信早期的JDK API

在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 out
    if (files != null) {
        for (int i = 0; i < files.length; i++) {
            ...
        }
    }
}

mm! 编码Java列表时,违反了我们的10条最佳最佳实践中的规则5和6。 因此,请做好准备并添加该null检查!

3.不要相信“ -1”

我知道这很偏执。 String.indexOf()的Javadoc明确指出……

返回此对象表示的字符序列中字符首次出现的索引(如果没有出现,则返回-1)。

因此, -1是理所当然的,对吧? 我说不。 考虑一下:

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

// Good
if (string.indexOf(character) >= 0) { ... }

谁知道。 也许他们需要在某个时间点进行ANOTHER编码,以便说,如果不区分大小写地检查, otherString包含otherString ……也许是返回-2的好例子? 谁知道。

毕竟, 关于十亿美元的错误 ,我们已经进行了数十亿次讨论,这是NULL 。 为什么我们不应该开始讨论-1 ,它在某种程度上是原始类型int的替代null

4.避免意外分配

是的 它发生的最好(尽管不是我。请参阅#7)。

(假设这是JavaScript,但是我们也要对语言保持偏执)

// Ooops
if (variable = 5) { ... }

// Better (because causes an error)
if (5 = variable) { ... }

// Intent (remember. Paranoid JavaScript: ===)
if (5 === variable) { ... }

再次。 如果您的表达式中有文字,请将其放在左侧。 当您打算添加另一个=符号时,您不会在这里偶然出错。

5.检查空AND长度

只要有集合,数组等,请确保其存在且不为空。

// Bad
if (array.length > 0) { ... }

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

您永远不知道这些数组从何而来。 也许来自早期的JDK API?

6.所有方法均为最终方法

您可以告诉我所有关于您的开放/封闭原则的信息,这些都是胡扯。 我不信任您(正确地扩展了我的课程),我也不信任自己(不偶然地扩展了我的课程)。 这就是为什么所有未明确打算用于子类型化的东西(即仅接口)都是final 。 另请参阅我们的《 编码Java的10条最佳实践》列表中的第9条。

// Bad
public void boom() { ... }

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

是。 这是最终的。 如果那对您不起作用,请对其进行修补或检测,或重写字节码。 或发送功能请求。 我敢肯定,您要覆盖上述内容并不是一个好主意。

7.所有变量和参数均为最终变量

就像我说的。 我不信任自己(不会意外覆盖我的价值观)。 话虽如此,我一点也不相信自己。 因为…

昨天正则表达式

…这就是为什么所有变量和参数也都设为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);
    else
        good(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);

相信我。 我已经看到了一切。 包括像

7h6fah71

偏执是很好的。

9.始终打开默认开关

切换...这些滑稽的陈述之一,我不知道该敬畏地吓呆还是哭泣。 无论如何,我们被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引入软件的那一刻,它一定会来! 不要说enum ,因为它会发生在enums的!

10.用花括号切换

实际上, 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语句与令人惊讶的FORTRAN 77 ENTRY语句进行比较, FORTRAN 77 ENTRY语句的神秘之处仅在于其强大功能。

这意味着变量final int j是针对所有不同情况定义的,无论我们是否发出break 。 不是很直观。 这就是为什么通过一个简单的block为每个case语句创建一个新的嵌套作用域始终是一个好主意的原因。 (但不要忘记块内的break !)

结论

有时偏执狂的编程似乎很奇怪,因为代码常常比实际需要的更为冗长。 您可能会想,“哦,这永远不会发生”,但是正如我所说。 经过20年左右的编程,您只是不想修复仅由于该语言太老和有缺陷而不再存在的那些愚蠢的,不必要的小错误。 因为你知道

现在轮到你了!

您在编程中最偏执的怪癖是什么?

翻译自: https://www.javacodegeeks.com/2015/08/top-10-useful-yet-paranoid-java-programming-techniques.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值