Переменные и типы данных

Переменная

Переменная связывает имя, статический тип и значение в некоторой области видимости.

int retryCount = 3;
String status = "READY";

Имя пишут в lowerCamelCase, константу — обычно в UPPER_SNAKE_CASE. Идентификатор не начинается с цифры и не может совпадать с ключевым словом. Главное правило — имя должно выражать роль, а не только тип: retryCount полезнее, чем number.

Примитивные типы

ТипРазмерДиапазон/смысл
byte8 битцелое -128..127
short16 битцелое -32768..32767
int32 битазнаковое целое
long64 битазнаковое целое
float32 битаIEEE 754, ограниченная точность
double64 битаIEEE 754, основной тип дробных вычислений
char16 биткодовая единица UTF-16, не всегда целый Unicode-символ
booleanJVM не задаёт размер переменнойtrue или false

Литерал целого по умолчанию имеет тип int, дробного — double:

long timeout = 10_000L;
float ratio = 0.75F;
int mask = 0b1010;
int color = 0xFF00AA;

Ссылочные типы

Ссылочная переменная хранит ссылку на объект либо null:

String first = new String("ok");
String second = first;

Здесь две переменные указывают на один объект. Присваивание ссылки не копирует объект. Конкретное представление ссылки в памяти не является частью языка Java.

Массивы, классы, интерфейсы, enum и record — ссылочные типы. Их поведение при передаче в метод связано с тем, что Java всегда передаёт аргументы по значению: для объекта копируется значение ссылки.

Инициализация и область видимости

Поля получают значения по умолчанию (0, false, null), локальные переменные компилятор требует явно инициализировать перед чтением.

class Counter {
    private int total; // 0
 
    int next(boolean increment) {
        int delta;
        if (increment) {
            delta = 1;
        } else {
            delta = 0;
        }
        return total += delta;
    }
}

Область видимости ограничена блоком { ... }. Чем уже область и короче жизнь переменной, тем проще проверить её состояние.

final и var

final запрещает повторно присвоить переменную, но не делает объект неизменяемым:

final List<String> names = new ArrayList<>();
names.add("Ada"); // допустимо
// names = new ArrayList<>(); // недопустимо

var просит компилятор вывести статический тип локальной переменной. Это не динамическая типизация:

var names = new ArrayList<String>(); // тип ArrayList<String>

var нельзя использовать для полей, параметров и возвращаемых типов. Он полезен, когда тип очевиден из правой части и имя сохраняет смысл.

char и Unicode

Один char — кодовая единица UTF-16. Символ за пределами Basic Multilingual Plane занимает пару char, поэтому String.length() считает кодовые единицы, а не пользовательские символы. Для Unicode-кода применяют методы codePoint....

Ловушки

  • Считать ссылку самим объектом или ожидать копию при присваивании.
  • Забывать суффиксы L и F.
  • Считать final List неизменяемым списком.
  • Использовать float/double для точных денежных сумм.
  • Считать, что любой Unicode-символ помещается в один char.
  • Давать var имя вроде data, скрывающее назначение значения.

Вопросы на собеседовании

  1. Чем примитивный тип отличается от ссылочного?
  2. Какие значения по умолчанию получают поля и локальные переменные?
  3. Делает ли final объект неизменяемым?
  4. Почему char не всегда равен одному символу?
  5. Является ли var динамической типизацией?
  6. Что именно передаётся в метод при передаче объекта?

Связанные заметки

Классы обертки Java · Преобразование типов Java · Работа с числовыми данными · Работа со строковыми данными · Объекты Java · Immutable классы и данные