Home >Java >javaTutorial >10 practical but paranoid Java programming techniques
After immersing yourself in coding for a period of time, you will gradually become accustomed to these things. Because, you know...
Anything can go wrong, yes, it does.
This is why we adopt "defensive programming", which is the reason for some paranoid habits. Below are what I personally consider to be the 10 most useful but paranoid Java programming techniques. Let’s take a look:
1. Put the String string at the front
In order to prevent occasional NullPointerException exceptions, we usually place String on the left side of the equals() function to implement string comparison. The following code:
// Bad if (variable.equals("literal")) { ... } // Good if ("literal".equals(variable)) { ... }
This is something you can do just by thinking about it. From the Bad version of the code to rewriting the expression to the Good version of the code, nothing will be lost in the process. Different opinions are welcome...
2. Don’t trust the early JDK API
In the early days of Java, programming was a very painful thing. Those APIs are still very immature, and maybe you've encountered the following code block:
String[] files = file.list(); // Watch out if (files != null) { for (int i = 0; i < files.length; i++) { ... } }
Looking paranoid? Maybe, but see the Javadoc:
If this virtual path does not represent a folder directory, this method returns null. Otherwise, an array of strings will be returned, each string representing a file or folder in the directory.
Yes, that’s right. We can add some verification:
if (file.isDirectory()) { String[] files = file.list(); // Watch out if (files != null) { for (int i = 0; i < files.length; i++) { ... } } }
3. Don’t believe “-1”
I know this is paranoid, but the Javadoc clearly points out the String.indexOf() method: the position of the first occurrence of the specified character in the object Index, if it is -1, it means that the character is not in the character sequence.
So using -1 is a no-brainer, right? I'm not sure, please look at the following code:
// Bad if (string.indexOf(character) != -1) { ... } // Good if (string.indexOf(character) >= 0) { ... }
Who knows. Maybe by then they've changed the encoding so that strings are not case-sensitive, and maybe a better way is to return -2? Who knows.
4. Avoid accidental assignment
Yes. This may happen often.
// Ooops if (variable = 5) { ... } // Better (because causes an error) if (5 = variable) { ... } // Intent (remember. Paranoid JavaScript: ===) if (5 === variable) { ... }
So you can place the comparison constant on the left side, so that accidental assignment errors will not occur.
5. Check Null and Length
No matter what, as long as you have a collection, array, etc., make sure it exists and is not empty.
// Bad if (array.length > 0) { ... } // Good if (array != null && array.length > 0) { ... }
You don’t know where these arrays come from, maybe from an earlier version of the JDK API, who knows.
6. All methods are final
You may tell me your open/closed principle, but this is all nonsense. I don't believe you (correctly inherit all subclasses of my parent class), and I don't believe myself (accidentally inherit all subclasses of my parent class). Therefore, methods with clear meaning should be strictly marked with final.
// Bad public void boom() { ... } // Good. Don't touch. public final void dontTouch() { ... }
7. All variables and parameters are final
Like I said. I don't trust myself (not to accidentally overwrite my values). Having said that, I don’t believe mine because…
…这就是为什么所有的变量和参数都是final的原因。
// Bad void input(String importantMessage) { String answer = "..."; answer = importantMessage = "LOL accident"; } // Good final void input(final String importantMessage) { final String answer = "..."; }
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);
相信我。这一切我都看到过。包括下面的
这种偏执还是不错的。
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时,将会出现无法找到的提示,而不会让人不知所谓。
10.Switch语句带花括号
事实上,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语句甚至不是真正的语句,他们就像goto语句中的跳转标记一样。
在switch语句中,每一个case语句的范围只有一行语句,事实上,这些case语句甚至不是真正的语句,他们就像goto语句中的跳转标记一样。
结论
偏执编程看起来似乎不可思议,有时,因为代码经常被证明是更详细一点,但并不是需求需要。你可能会想,“哦,这是绝不会发生的”,但正如我所说。经过20年左右的时间编程,你不希望只修复这些愚蠢的bug,因为编程语言是如此的陈旧的和有缺陷的。因为你知道…