Статьи

Топ 10 полезных, но параноидальных методов программирования Java

После некоторого программирования (например, почти 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);

Доверьтесь мне. Я видел все. Включая такие вещи, как

7H6FAH7 [1]

Хорошо быть параноиком.

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 лет программирования вы просто не хотите больше исправлять эти глупые маленькие ненужные ошибки, которые существуют только потому, что язык настолько стар и несовершенен. Потому что ты знаешь …

Теперь твоя очередь!

Какой твой самый параноидальный изюминка в программировании?

Читать дальше

Вам понравился этот список? Есть больше свободного времени, чтобы тратить на списки? У нас есть больше. Здесь: