Если передать значение примитивного типа в метод, оно будет скопировано:
public static void main(String[] args) {
// объявляем переменную примитивного типа
int voltage = 4100;
// передаём
add100mV(voltage);
// 4100 — без изменений
System.out.println(voltage);
}
private static void add100mV(int lowVoltage) {
lowVoltage += 100;
// Абсолютно бесполезное действие.
// Переменная lowVoltage существует
// только в пределах метода и уничтожается,
// когда метод отработал.
}
Если передать объект в метод, будет передана ссылка на этот объект, т. е. в методе будет доступен тот же объект, не копия.
public static void main(String[] args) {
int[] voltages = {4100};
// массивы в Java — это объекты.
add100mVToFirstElement(voltages); // передаём
System.out.println(voltages[0]); // 4200
}
private static void add100mVToFirstElement(int[] lowVoltages) {
lowVoltages[0] += 100;
// Локальная переменная lowVoltages
// указывает на массив,
// мы прибавляем 100 мВ
// к значению нулевого элемента
// этого массива.
}
Это называется «передача по значению» и «передача по указателю (ссылке)» соответственно.
Кроме того, что можно указывать на объекты (например, int[] voltages = {4100}; или Phone myPhone = new Nexus5();), также можно указывать на пустое значение.
public static void main(String[] args) {
int[] voltages = null;
// пустой указатель
add100mVToFirstElement(voltages); // передаём
}
private static void add100mVToFirstElement(int[] lowVoltages) {
lowVoltages[0] += 100;
}
Результат:
Exception in thread "main" java.lang.NullPointerException at JavaneseNull.add100mVToFirstElement(JavaneseNull.java:11) at JavaneseNull.main(JavaneseNull.java:8)
Выполнение программы прервалось, т. к. произошла попытка чтения элемента из null. Ещё один пример безнадёжного кода:
MobilePhone mp = null;
mp.dial("*#06#");
null существует, чтобы показать отсутствие значения. Любая переменная объектного (ссылочного) типа, переданная извне, может оказаться null, поэтому в методах нужно проверять входные данные. Например:
private static void add100mVToFirstElement(int[] lowVoltages) {
if (lowVoltages == null)
throw new NullPointerException("lowVoltages == null, ожидался массив");
if (lowVoltages.length < 1)
throw new IllegalArgumentException("lowVoltages.length < 1, ожидался массив хотя бы с одним элементом");
lowVoltages[0] += 100;
}
Если аргумент lowVoltages не пройдёт проверку, выполнение будет прервано с выбросом соответствующего исключения.
Если передать null:
Если передать пустой массив:
Непустой массив:
Успех!
Аннотации для борьбы с нулевыми указателями (null pointers)
Чтобы показать, что поле или параметр может быть null или метод может вернуть null, используется аннотация @Nullable.
@Nullable
private String toBeOrNotToBe;
@Nullable
public String toBeOrNotToBe() {
return toBeOrNotToBe;
}
Чтобы, наоборот, показать, что поле или параметр не может быть null или метод не может вернуть null, используется аннотация @NotNull или @NonNull.
@NotNull
private final String name;
public User(@NotNull String name) {
this.name = name;
}
Эти аннотации помогают среде разработки определить, где могут быть null, и предостеречь о возможных ошибках.