Це для мене звучить як досить поширена проблема, з якою в деякий момент стикаються розробники молодших та проміжних рівнів: вони або не знають, або не довіряють контрактам, в яких беруть участь, і оборонно переглядають нулі. Крім того, під час написання власного коду вони схильні розраховувати на повернення нулів, щоб вказати щось, тим самим вимагаючи, щоб абонент перевіряв наявність нулів.
Інакше кажучи, є два випадки, коли виникає перевірка нуля:
Де null є вагомою відповіддю з точки зору договору; і
Якщо це неправдива відповідь.
(2) легко. Або використовуйте assert
оператори (твердження) або дозвольте відмову (наприклад, NullPointerException ). Твердження - це сильно використана функція Java, яка була додана в 1.4. Синтаксис:
assert <condition>
або
assert <condition> : <object>
де <condition>
булевий вираз і <object>
є об'єктом, toString()
вихід якого методу буде включений у помилку.
assert
Заява кидає Error
( AssertionError
) , якщо умова не виконується. За замовчуванням Java ігнорує твердження. Ви можете ввімкнути твердження, передавши опцію -ea
в JVM. Ви можете вмикати та вимикати твердження для окремих класів та пакетів. Це означає, що ви можете перевірити код за твердженнями під час розробки та тестування та відключити їх у виробничому середовищі, хоча моє тестування показало, що поруч із твердженнями не впливає на ефективність.
Не використовувати твердження в цьому випадку нормально, оскільки код просто вийде з ладу, що і станеться, якщо ви будете використовувати твердження. Єдина відмінність полягає в тому, що з твердженнями це може статися раніше, більш змістовно і, можливо, з додатковою інформацією, яка може допомогти вам зрозуміти, чому це сталося, якщо ви цього не очікували.
(1) трохи складніше. Якщо у вас немає контролю над кодом, який ви телефонуєте, то ви застрягли. Якщо null є дійсною відповіддю, ви повинні перевірити її.
Якщо ви керуєте цим кодом (і це часто буває), то це вже інша історія. Уникайте використання нулів як відповіді. З методами, що повертають колекції, це просто: повертайте порожні колекції (або масиви) замість нулів майже весь час.
З неприйнятими колекціями це може бути складніше. Розглянемо це як приклад: якщо у вас є такі інтерфейси:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
де Парсер приймає необмежену інформацію користувача і знаходить щось робити, можливо, якщо ви реалізуєте інтерфейс командного рядка для чогось. Тепер ви можете укласти договір про те, що він повертає недійсним, якщо немає відповідних дій. Це призводить до перевірки нуля, про яку ви говорите.
Альтернативне рішення - ніколи не повертати null і замість цього використовувати шаблон Null Object :
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
Порівняйте:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
до
ParserFactory.getParser().findAction(someInput).doSomething();
що є набагато кращим дизайном, оскільки призводить до більш короткого коду.
З цього приводу, можливо, цілком доречно для методу findAction () кинути виняток із змістовним повідомленням про помилку - особливо в цьому випадку, коли ви покладаєтесь на введення користувача. Було б набагато краще, щоб метод findAction кинув виняток, ніж метод виклику, щоб підірвати простий NullPointerException без пояснень.
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
Або якщо ви вважаєте, що механізм "пробувати / ловити" занадто некрасиво, а не робити нічого, ваші дії за замовчуванням не повинні надавати відгуку користувачу.
public Action findAction(final String userInput) {
/* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}