Я думаю, что вы выдвинули более важный вопрос, стоящий за первоначальным: стоит ли работать над предотвращением исключительных случаев в методах получения и установки?
Ответ - да, вы должны работать, чтобы избежать тривиальных исключений.
То, что у вас здесь есть, действительно ленивый экземпляр , который совсем не мотивирован в этом примере:
В компьютерном программировании ленивая инициализация - это тактика задержки
создание объекта, расчет стоимости или какой-либо другой
дорогой процесс, пока в первый раз он не понадобится.
В этом примере у вас есть две проблемы:
Ваш пример не безопасен для потоков. Эта проверка на нулевое значение может быть успешной (то есть обнаружить, что объект является нулевым) в двух потоках одновременно. Затем ваш экземпляр создает два разных списка строк. Произойдет недетерминированное поведение.
В этом примере нет веской причины откладывать создание экземпляра. Это не дорогая или сложная операция. Это то, что я имею в виду под «работой, чтобы избежать тривиальных исключений»: стоит инвестировать циклы, чтобы создать полезный (но пустой) список, чтобы убедиться, что вы не выбрасываете исключения нулевого указателя с задержкой детонации.
Помните, что когда вы вызываете исключение для внешнего кода, вы в основном надеетесь, что разработчики знают, как сделать что-то разумное с ним. Вы также надеетесь на то, что в уравнении нет третьего разработчика, который обернул бы все в обработчике исключений, просто чтобы поймать и игнорировать исключения, подобные вашему:
try {
// I don't understand why this throws an exception. Ignore.
t.getStrings();
} catch (Exception e) {
// Ignore and hope things are fine.
}
В приведенном ниже примере я использую шаблон Null Object , чтобы указать будущему коду, что ваш пример не был установлен. Однако Null Object запускается как неисключительный код и, следовательно, не имеет накладных расходов и не влияет на рабочий процесс будущих разработчиков.
public class App {
static class Test {
// Empty list
public static final List<String> NULL_OBJECT = new ArrayList<String>();
private List<String> strings = NULL_OBJECT;
public synchronized List<String> getStrings() {
return strings;
}
public synchronized void setStrings(List<String> strings) {
this.strings = strings;
}
}
public static void main(String[] args) {
Test t = new Test();
List<String> s = t.getStrings();
if (s == Test.NULL_OBJECT) {
// Do whatever is appropriate without worrying about exception
// handling.
// A possible example below:
s = new ArrayList<String>();
t.setStrings(s);
}
// At this point, s is a useful reference and
// t is in a consistent state.
}
}