После некоторого программирования (например, почти 20 лет в моем случае время летит, когда вам весело), вы начинаете воспринимать эти привычки. Потому что, ты знаешь …
Все, что может пойти не так, делает.
Вот почему люди используют «защитное программирование», то есть параноидальные привычки, которые иногда имеют полный смысл, а иногда являются довольно неясными и / или умными и, возможно, немного жуткими, когда вы думаете о человеке, который написал это. Вот мой личный список из 10 лучших, но параноидальных техник программирования Java. Поехали:
1. Сначала поместите строковый литерал
Просто никогда не плохая идея предотвратить случайность NullPointerException
, поместив String
литерал в левой части equals()
сравнения как таковой:
// Bad
if (variable.equals("literal")) { ... }
// Good
if ("literal".equals(variable)) { ... }
Это ежу понятно. Ничто не потеряно от перефразирования выражения от менее хорошей версии к лучшей. Если бы у нас были настоящие Варианты, правда? Разное обсуждение …
2. Не доверяйте ранним API JDK
В первые дни Java программирование, должно быть, было большой болью. API были все еще очень незрелыми, и вы, возможно, натолкнулись на фрагмент кода, подобный этому:
String[] files = file.list();
// Watch out
if (files != null) {
for (int i = 0; i < files.length; i++) {
...
}
}
Выглядит параноиком? Возможно, но читайте Javadoc :
Если это абстрактное имя пути не обозначает каталог, тогда этот метод возвращает ноль. В противном случае возвращается массив строк, по одной для каждого файла или каталога в каталоге.
Да правильно. Лучше добавить еще один чек, чтобы быть уверенным:
if (file.isDirectory()) {
String[] files = file.list();
// Watch out
if (files != null) {
for (int i = 0; i < files.length; i++) {
...
}
}
}
Облом! Нарушение правил № 5 и № 6 наших 10 тонких рекомендаций при написании кода Java . Так что будьте готовы и добавьте эту null
проверку!
3. Не верь, что «-1»
Это параноик, я знаю. Javadoc String.indexOf()
четко заявляет, что …
возвращается индекс первого вхождения символа в последовательности символов, представленной этим объектом, или -1, если символ не встречается.
Таким образом, -1
можно принять как должное, верно? Я говорю нет. Учти это:
// Bad
if (string.indexOf(character) != -1) { ... }
// Good
if (string.indexOf(character) >= 0) { ... }
Кто знает. Возможно, в какой-то момент им понадобится ДРУГОЕ кодирование, чтобы сказать, otherString
что они будут содержаться, если их проверять без учета регистра… Возможно, это хороший случай для возврата -2
? Кто знает.
В конце концов, у нас были миллиарды дискуссий о миллиардной ошибке, которая естьNULL
. Почему бы нам не начать дискуссии о том -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. Проверьте для нулевого и длины
Всякий раз, когда у вас есть коллекция, массив и т. Д., Убедитесь, что она присутствует и не пуста.
// Bad
if (array.length > 0) { ... }
// Good
if (array != null && array.length > 0) { ... }
Вы никогда не знаете, откуда взялись эти массивы. Возможно из раннего JDK API?
6. Все методы являются окончательными
Вы можете сказать мне все, что вы хотите о ваших принципах открытого / закрытого, это все бред. Я не доверяю вам (чтобы правильно продлить мои занятия) и не доверяю себе (чтобы не случайно продлить мои занятия). Вот почему все, что явно не предназначено для подтипирования (то есть только интерфейсы), строго final
. См. Также пункт № 9 из нашего списка 10 тонких рекомендаций при кодировании Java .
// 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);
Доверьтесь мне. Я видел все. Включая такие вещи, как
Хорошо быть параноиком.
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 , устройством, тайна которого превосходит только его мощь.
Это означает, что переменная final int j
определена для всех разных случаев, независимо от того, выдаём мы break
или нет. Не очень интуитивно понятно. Вот почему всегда полезно создать новую вложенную область видимости для каждого case
оператора с помощью простого блока . (но не забывайте break
внутри блока!)
Вывод
Параноидальное программирование иногда может показаться странным, так как код часто оказывается более многословным, чем действительно необходимо. Вы можете подумать: «О, этого никогда не случится», но, как я уже сказал. Приблизительно после 20 лет программирования вы просто не хотите больше исправлять эти глупые маленькие ненужные ошибки, которые существуют только потому, что язык настолько стар и несовершенен. Потому что ты знаешь …
Теперь твоя очередь!
Какой твой самый параноидальный изюминка в программировании?
Читать дальше
Вам понравился этот список? Есть больше свободного времени, чтобы тратить на списки? У нас есть больше. Здесь:
- 10 самых досадных вещей, возвращающихся на Яву после нескольких дней Scala
- Топ 10 очень, очень очень важные темы для обсуждения
- Топ 10 простых оптимизаций производительности в Java
- Лучшие 10 особенностей языка Цейлона, которые я хотел бы иметь на Java
- 10 вещей, которые каждый делает неправильно при совершении запросов на вытягивание
- 10 тонких ошибок при использовании API Streams