← назад к разделу

Если вы уже писали код на другом языке, Java покажется одновременно знакомой и непривычно строгой. Здесь у каждой переменной заранее объявлен тип, программа не запустится, пока не скомпилируется, а часть привычных вольностей просто запрещена. Разберём базу: как объявить переменную, чем int отличается от Integer, почему строки нельзя изменить и из чего состоит управляющая логика.

Зачем такая строгость

Java — язык со статической типизацией. Это значит, что тип каждой переменной известен ещё до запуска программы, на этапе компиляции. Компилятор проверяет, что вы не складываете число со списком и не вызываете у строки несуществующий метод. Ошибки такого рода ловятся сразу, а не во время работы у пользователя.

Короткая формула: в Java сначала компиляция, потом запуск. Исходный код (.java) превращается в байт-код (.class), который исполняет виртуальная машина JVM. Поэтому опечатка в имени метода — это не падение на проде, а ошибка сборки прямо в редакторе.

Точка входа: метод main

Любая Java-программа начинается с метода main. JVM ищет именно его и запускает первым:

public class App {
    public static void main(String[] args) {
        System.out.println("Привет, Java"); // вывод строки в консоль
    }
}

Разберём сигнатуру по словам:

  • public — метод доступен извне, JVM должна его увидеть;
  • static — метод принадлежит классу, а не объекту, его можно вызвать без создания экземпляра;
  • void — метод ничего не возвращает;
  • String[] args — массив аргументов командной строки.

Пока достаточно запомнить эту строку как «волшебное заклинание старта». Что такое class, public и static на самом деле — подробно в статье про ООП.

Переменные и var

Переменная объявляется по схеме «тип имя = значение»:

int age = 30;
String name = "Анна";
boolean active = true;

Тип слева обязателен — компилятор должен знать, что вы собираетесь хранить. Но с Java 10 появилось ключевое слово var: оно просит компилятор вывести тип автоматически из правой части.

var age = 30;          // компилятор видит число → int
var name = "Анна";     // видит строку → String
var items = new ArrayList<String>(); // тип ясен из конструктора

Важно: var — это не «нетипизированная» переменная, как в динамических языках. Тип всё равно фиксируется намертво, просто его не нужно писать руками. Записать потом в age строку нельзя. И var работает только там, где тип очевиден из значения, — для локальных переменных внутри методов.

Примитивы против объектов

В Java есть два мира значений.

Примитивные типы — это «голые» значения, лежащие в памяти напрямую. Их восемь, но на старте важны эти:

int count = 100;        // целое, 32 бита
long big = 9_000_000L;  // большое целое, 64 бита (подчёркивания для читаемости)
double price = 19.99;   // дробное
boolean ok = false;     // true / false
char letter = 'A';      // один символ в одинарных кавычках

Объектные (ссылочные) типы — это всё остальное: строки, списки, ваши собственные классы. Переменная хранит не само значение, а ссылку на объект в памяти. У каждого примитива есть объектный «двойник»-обёртка: intInteger, longLong, booleanBoolean, doubleDouble.

Зачем нужны обёртки? Многие части стандартной библиотеки (например, коллекции) умеют работать только с объектами, а не с примитивами. В список нельзя положить int, но можно Integer.

Автобоксинг

Чтобы не переключаться между мирами вручную, Java делает преобразование сама — это автобоксинг (примитив → обёртка) и анбоксинг (обёртка → примитив):

Integer boxed = 5;   // автобоксинг: int 5 → Integer
int back = boxed;    // анбоксинг: Integer → int

Удобно, но есть две ловушки. Первая: обёртка может быть null, и попытка распаковать null в примитив уронит программу с NullPointerException. Вторая: обёртки нужно сравнивать через .equals(), а не через == — про это в статье об исключениях и в материале про коллекции. Правило простое: если значение точно есть и оно одно — берите примитив int; если значение может отсутствовать или его надо положить в коллекцию — берите Integer.

Строки и их неизменяемость

String — это объект, и в Java строки неизменяемы (immutable). Любая операция, которая «меняет» строку, на самом деле создаёт новую, а старая остаётся прежней:

String greeting = "Привет";
String full = greeting + ", мир"; // создалась НОВАЯ строка
// greeting по-прежнему "Привет"

Это сделано ради безопасности и предсказуемости: раз строку нельзя испортить, её можно спокойно передавать куда угодно и использовать как ключ. Минус — если в цикле склеивать тысячи строк через +, каждый раз создаётся новый объект. Для такого случая есть StringBuilder:

var sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
    sb.append(i).append(' '); // меняем один и тот же буфер
}
String result = sb.toString(); // "0 1 2 3 4 "

Ещё две полезные мелочи. Сравнивать строки по содержимому нужно через .equals(), а не == (последнее сравнивает ссылки). А с Java 15 для многострочного текста есть «текстовые блоки» в тройных кавычках:

String json = """
        {
          "name": "Анна"
        }
        """;

Операторы

Операторы в Java привычны почти любому программисту:

int sum = 2 + 3;        // арифметика: + - * / %
boolean adult = age >= 18;     // сравнение: == != < > <= >=
boolean both = active && adult; // логика: && (и), || (или), ! (не)

Логические && и || «ленивы»: если левая часть && уже false, правую Java даже не вычисляет. Это удобно для проверок вида if (user != null && user.isActive()) — второе условие не выполнится, если user равен null.

Есть и тернарный оператор — короткая форма выбора одного из двух значений:

String label = adult ? "взрослый" : "несовершеннолетний";

Управляющие конструкции

Ветвлениеif / else if / else:

if (price > 100) {
    System.out.println("дорого");
} else if (price > 50) {
    System.out.println("средне");
} else {
    System.out.println("дёшево");
}

Циклыfor, while и for-each для перебора коллекций:

for (int i = 0; i < 3; i++) {       // классический счётчик
    System.out.println(i);
}

int n = 3;
while (n > 0) {                      // пока условие истинно
    n--;
}

var names = List.of("Анна", "Борис");
for (String person : names) {        // for-each: по каждому элементу
    System.out.println(person);
}

Выбор по значениюswitch. В современной Java есть короткая стрелочная форма, которая может сразу возвращать результат и не требует break:

String role = "admin";
int level = switch (role) {
    case "admin" -> 3;
    case "editor" -> 2;
    default -> 1;            // обязательная ветка «всё остальное»
};

Старая форма с case ... : и break тоже работает, но стрелочный switch короче и не даёт случайно «провалиться» в следующую ветку.

Коротко

  • Java — статически типизированный язык: тип известен на этапе компиляции, ошибки ловятся до запуска.
  • Любая программа стартует с метода public static void main(String[] args).
  • var не отменяет типизацию — он лишь выводит тип автоматически для локальных переменных.
  • Примитивы (int, double, boolean) хранят значение напрямую; объектные обёртки (Integer, Double) могут быть null и нужны для коллекций. Перевод между ними — автобоксинг.
  • Строки неизменяемы: «изменение» создаёт новый объект; для активной склейки используйте StringBuilder, для сравнения — .equals().
  • Управляющие конструкции стандартны: if/else, for, while, for-each и современный стрелочный switch.

Что почитать дальше

  • ООП в Java: классы, объекты, наследование — что на самом деле стоит за class, public и static.
  • Коллекции Java — где обёртки Integer и неизменяемость строк проявляются на практике.
  • Инструменты Java-разработчика — как собрать и запустить код, который мы здесь писали.