инициализация
Как правило, попробуйте инициализировать переменные, когда они объявлены.
Если значение переменной не предназначено для изменения, сделайте это явным, используя ключевое слово final
. Это поможет вам понять правильность вашего кода, и хотя я не знаю об оптимизации компилятора или JVM, которая распознает ключевое слово final
, они, безусловно, были бы возможны.
Конечно, есть исключения из этого правила. Например, переменная может быть назначена в if - else или переключателе. В таком случае «пустое» объявление (без инициализации) предпочтительнее инициализации, которая гарантированно будет перезаписана до считывания фиктивного значения.
/* DON'T DO THIS! */
Color color = null;
switch(colorCode) {
case RED: color = new Color("crimson"); break;
case GREEN: color = new Color("lime"); break;
case BLUE: color = new Color("azure"); break;
}
color.fill(widget);
Теперь у вас есть NullPointerException
, если представлен нераспознанный цветовой код. Было бы лучше не назначать бессмысленные null
. Компилятор выдаст ошибку при вызове color.fill()
, потому что он обнаружит, что вы, возможно, не инициализировали color
.
Чтобы ответить на ваш вопрос в этом случае, мне нужно увидеть соответствующий код. Если решение инициализировало его внутри метода run()
, оно должно было использоваться либо как временное хранилище, либо как способ «возврата» результатов задачи.
Если коллекция используется как временное хранилище и недоступна вне метода, она должна быть объявлена как локальная переменная, а не переменная экземпляра, и, скорее всего, должна быть инициализирована там, где она объявлена в методе.
Проблемы параллелизма
На начальном курсе программирования ваш инструктор, вероятно, не пытался столкнуть вас со сложностями параллельного программирования - хотя, если это так, я не уверен, почему вы использовали Thread
. Но с учетом современных тенденций в разработке процессоров каждый, кто учится программировать, должен иметь четкое представление о параллелизме. Я попытаюсь вникнуть немного глубже.
Возвращать результаты из метода run
потока немного сложно. Этот метод является интерфейсом Runnable , и ничто не мешает нескольким потокам выполнить метод run
одного экземпляра. Возникшие в результате проблемы параллелизма являются частью мотивации интерфейса Callable , представленного в Java 5. Он очень похож на Runnable
, но может возвращать результат в поточно-ориентированном режиме и выдает Exception
, если задание не может быть выполнено.
Это немного отступает, но если вам интересно, рассмотрите следующий пример:
class Oops extends Thread { /* Note that thread implements "Runnable" */
private int counter = 0;
private Collection<Integer> state = ...;
public void run() {
state.add(counter);
counter++;
}
public static void main(String... argv) throws Exception {
Oops oops = new Oops();
oops.start();
Thread t2 = new Thread(oops); /* Now pass the same Runnable to a new Thread. */
t2.start(); /* Execute the "run" method of the same instance again. */
...
}
}
К концу метода main
вы почти не представляете, что такое "состояние" Collection
. Два потока работают над этим одновременно, и мы не указали, является ли коллекция безопасной для одновременного использования. Если мы инициализируем его внутри потока, по крайней мере, мы можем сказать, что в конечном итоге state
будет содержать один элемент, но мы не можем сказать, 0 или 1.