LEARN X · ЗА 18 МИН

Java

Весь Java на одной странице: типы, строки, циклы, массивы, коллекции, ООП, наследование, интерфейсы, исключения, дженерики и Stream API в комментариях кода.

Java — строго типизированный объектно-ориентированный язык со статической компиляцией в байт-код JVM. Здесь весь язык на одной странице: почти без прозы, всё объяснение живёт в комментариях кода. Читай сверху вниз — каждый блок компилируется, а результат указан в комментариях.

1. Структура программы

Точка входа — метод main внутри класса. Имя файла должно совпадать с именем публичного класса (Main.java).

// Однострочный комментарий
/* Многострочный
   комментарий */
/** Javadoc-комментарий для документации */

public class Main {
    // public static void main(String[] args) — обязательная сигнатура точки входа
    public static void main(String[] args) {
        System.out.println("Привет, Java!"); // вывод с переводом строки -> Привет, Java!
        System.out.print("без переноса");      // вывод без \n
        System.out.printf("%s = %d%n", "x", 42); // форматный вывод -> x = 42
    }
}

2. Переменные и типы

Восемь примитивных типов хранят значение напрямую; объекты хранятся по ссылке.

// --- Примитивы (значение хранится напрямую) ---
int i = 42;                 // целое 32 бита
long big = 9_000_000_000L;  // 64 бита, суффикс L; _ — разделитель разрядов
short s = 100;              // 16 бит
byte b = 127;               // 8 бит
double d = 3.14;            // дробное 64 бита (по умолчанию для дробных)
float f = 3.14f;            // 32 бита, суффикс f
boolean flag = true;        // true / false
char c = 'A';               // одиночный символ в одинарных кавычках (Unicode)

// --- var: вывод типа компилятором (с Java 10) ---
var name = "Аня";   // компилятор выводит String
var count = 10;       // компилятор выводит int

// --- Примитивы vs объекты ---
int prim = 5;            // примитив
Integer obj = 5;         // объект-обёртка (autoboxing); может быть null
long max = Long.MAX_VALUE;        // 9223372036854775807
String text = Integer.toString(prim); // "5"
int parsed = Integer.parseInt("123"); // 123

final double PI = 3.14159; // final — константа, переприсвоить нельзя

3. Строки

Строки неизменяемы (immutable). Для частой конкатенации используют StringBuilder.

String str = "Hello, Java";

str.length();              // 11 — длина
str.charAt(0);             // 'H' — символ по индексу
str.substring(7);          // "Java" — подстрока с индекса
str.substring(0, 5);       // "Hello" — [0;5)
str.indexOf("Java");       // 7 — позиция подстроки
str.toUpperCase();         // "HELLO, JAVA"
str.replace("Java", "Kt"); // "Hello, Kt"
str.contains("Java");      // true
str.split(", ");           // ["Hello", "Java"]
"  отступ  ".trim();        // "отступ" — обрезка пробелов
"a".equals("a");           // true — сравнение содержимого (== сравнивает ссылки!)

// Конкатенация
String full = "abc" + 1 + true; // "abc1true"

// StringBuilder — изменяемая строка (быстро для циклов)
StringBuilder sb = new StringBuilder();
sb.append("раз").append("-").append(2);
sb.toString();             // "раз-2"

// Форматирование
String.format("%s: %d (%.2f)", "sum", 10, 3.5); // "sum: 10 (3.50)"

// Текстовый блок (с Java 15) — многострочная строка
String json = """
    {"name": "Аня"}
    """;

4. Операторы и условия

// Арифметика: + - * / %  (целочисленное деление отбрасывает дробь)
7 / 2;   // 3
7 % 2;   // 1 (остаток)
7.0 / 2; // 3.5

// Сравнение: == != < > <= >=
// Логика: && (и), || (или), ! (не)

int age = 18;
if (age >= 18) {
    System.out.println("взрослый");
} else if (age >= 14) {
    System.out.println("подросток");
} else {
    System.out.println("ребёнок");
}

// Тернарный оператор: условие ? если_да : если_нет
String status = age >= 18 ? "можно" : "нельзя"; // "можно"

// switch (классический)
int day = 3;
switch (day) {
    case 1: System.out.println("Пн"); break; // break обязателен, иначе провал
    case 3: System.out.println("Ср"); break;
    default: System.out.println("?");
}

// switch-выражение со стрелкой (с Java 14) — возвращает значение, без break
String name = switch (day) {
    case 1 -> "Понедельник";
    case 3 -> "Среда";
    default -> "Другой";
}; // "Среда"

5. Циклы

// for: инициализация; условие; шаг
for (int i = 0; i < 3; i++) {
    System.out.print(i); // 012
}

// for-each: перебор элементов коллекции/массива
int[] nums = {10, 20, 30};
for (int n : nums) {
    System.out.print(n + " "); // 10 20 30
}

// while: пока условие истинно
int k = 0;
while (k < 3) {
    k++;
} // k == 3

// do-while: тело выполняется хотя бы раз
int m = 0;
do {
    m++;
} while (m < 0); // m == 1 (вошли один раз)

// break — выход, continue — к следующей итерации
for (int i = 0; i < 10; i++) {
    if (i == 2) continue; // пропустить 2
    if (i == 5) break;    // остановиться на 5
    System.out.print(i);  // 0134
}

6. Массивы

Массивы фиксированной длины, индексация с нуля.

// Объявление и создание
int[] a = new int[3];      // [0, 0, 0] — заполнен нулями
a[0] = 5;                  // присваивание по индексу
a.length;                  // 3 — длина (поле, не метод!)

// Инициализация литералом
int[] b = {1, 2, 3, 4};
String[] names = {"Аня", "Боб"};

// Перебор
for (int i = 0; i < b.length; i++) {
    System.out.print(b[i]); // 1234
}

// Многомерный массив (матрица)
int[][] grid = {
    {1, 2, 3},
    {4, 5, 6}
};
grid[1][2]; // 6 — строка 1, столбец 2

// Утилиты Arrays
import java.util.Arrays;
int[] c = {3, 1, 2};
Arrays.sort(c);            // [1, 2, 3] — сортировка на месте
Arrays.toString(c);        // "[1, 2, 3]" — для печати
int[] d = Arrays.copyOf(c, 5); // [1, 2, 3, 0, 0]

7. Коллекции

Из пакета java.util. В угловых скобках — дженерик-тип элементов.

import java.util.*;

// --- ArrayList: динамический список ---
List<String> list = new ArrayList<>();
list.add("a");           // [a]
list.add("b");           // [a, b]
list.get(0);             // "a"
list.set(0, "z");        // [z, b]
list.remove("b");        // [z]
list.size();             // 1
list.contains("z");      // true

// --- HashMap: ключ -> значение ---
Map<String, Integer> ages = new HashMap<>();
ages.put("Аня", 25);     // добавить пару
ages.put("Боб", 30);
ages.get("Аня");         // 25
ages.getOrDefault("Ева", 0); // 0 — значение по умолчанию
ages.containsKey("Боб"); // true
for (Map.Entry<String, Integer> e : ages.entrySet()) {
    System.out.println(e.getKey() + "=" + e.getValue());
}

// --- HashSet: множество уникальных значений ---
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(1);              // дубликат игнорируется
set.add(2);
set.size();              // 2

8. Методы

// Объявление: модификатор тип_возврата имя(параметры)
static int sum(int x, int y) {
    return x + y; // возврат значения
}

static void greet(String name) { // void — ничего не возвращает
    System.out.println("Привет, " + name);
}

// Перегрузка: одно имя, разные параметры
static int multiply(int a, int b)    { return a * b; }
static double multiply(double a, double b) { return a * b; }
// multiply(2, 3) -> 6 ; multiply(2.0, 3.0) -> 6.0

// varargs: переменное число аргументов (внутри — массив)
static int total(int... nums) {
    int s = 0;
    for (int n : nums) s += n;
    return s;
}
// total(1, 2, 3) -> 6 ; total() -> 0

9. Классы и ООП

public class Person {
    // Поля (private — инкапсуляция: доступ только через методы)
    private String name;
    private int age;

    // Конструктор — инициализирует объект
    public Person(String name, int age) {
        this.name = name; // this — ссылка на текущий объект
        this.age = age;
    }

    // Геттеры / сеттеры — контролируемый доступ к полям
    public String getName() { return name; }
    public void setAge(int age) {
        if (age >= 0) this.age = age; // валидация
    }

    public String greet() {
        return "Я " + name + ", мне " + age;
    }
}

// Использование
Person p = new Person("Аня", 25); // new вызывает конструктор
p.getName();  // "Аня"
p.setAge(26);
p.greet();    // "Я Аня, мне 26"

10. Наследование и полиморфизм

// abstract — нельзя создать напрямую, только наследовать
abstract class Animal {
    protected String name; // protected — виден потомкам
    Animal(String name) { this.name = name; }

    abstract String sound(); // абстрактный метод — без тела, потомок обязан реализовать

    String describe() { return name + " говорит " + sound(); }
}

class Dog extends Animal {           // extends — наследование
    Dog(String name) { super(name); } // super — вызов конструктора родителя

    @Override // аннотация: переопределяем метод родителя
    String sound() { return "Гав"; }
}

class Cat extends Animal {
    Cat(String name) { super(name); }
    @Override String sound() { return "Мяу"; }
}

// Полиморфизм: один тип-ссылка — разное поведение
Animal a = new Dog("Рекс");
a.describe();          // "Рекс говорит Гав"
a = new Cat("Барсик");
a.describe();          // "Барсик говорит Мяу"

11. Интерфейсы

Контракт без состояния. Класс может реализовать несколько интерфейсов.

interface Drawable {
    void draw(); // абстрактный метод (по умолчанию public abstract)

    // default-метод — реализация по умолчанию (с Java 8)
    default void clear() {
        System.out.println("очищено");
    }
}

interface Resizable {
    void resize(double factor);
}

// implements — реализация интерфейса(ов), можно несколько через запятую
class Circle implements Drawable, Resizable {
    double r = 1.0;
    @Override public void draw() { System.out.println("○ r=" + r); }
    @Override public void resize(double f) { r *= f; }
}

Drawable shape = new Circle();
shape.draw();  // ○ r=1.0
shape.clear(); // очищено (default-метод)

12. Исключения

Checked-исключения нужно объявлять/обрабатывать; unchecked (RuntimeException) — нет.

try {
    int x = 10 / 0;          // выбросит ArithmeticException (unchecked)
} catch (ArithmeticException e) {
    System.out.println("Ошибка: " + e.getMessage()); // Ошибка: / by zero
} finally {
    System.out.println("finally — выполнится всегда");
}

// Несколько catch + общий тип
try {
    String s = null;
    s.length();              // NullPointerException
} catch (NullPointerException | IllegalArgumentException e) {
    System.out.println("поймано: " + e.getClass().getSimpleName());
}

// throw — выброс вручную; throws — объявление checked-исключения
static void check(int age) {
    if (age < 0) throw new IllegalArgumentException("возраст < 0");
}

// checked-исключение нужно объявить через throws
static void read() throws java.io.IOException {
    throw new java.io.IOException("нет файла");
}

// try-with-resources — авто-закрытие ресурса (AutoCloseable)
// try (var reader = new BufferedReader(...)) { ... } // close() вызовется сам

13. Дженерики и Stream API

import java.util.*;
import java.util.stream.*;

// --- Дженерики: параметризация типом <T> ---
class Box<T> {            // T — параметр-тип
    private T value;
    void set(T v) { value = v; }
    T get() { return value; }
}
Box<String> box = new Box<>();
box.set("привет");
box.get();               // "привет" — без приведения типов

// Дженерик-метод
static <T> T first(List<T> list) { return list.get(0); }

// --- Stream API: декларативная обработка коллекций ---
List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);

// filter -> map -> collect
List<Integer> result = nums.stream()
    .filter(n -> n % 2 == 0)   // оставить чётные: 2,4,6
    .map(n -> n * n)           // возвести в квадрат: 4,16,36
    .collect(Collectors.toList()); // [4, 16, 36]

// Свёртка к одному значению
int sum = nums.stream()
    .mapToInt(Integer::intValue)  // ссылка на метод
    .sum();                       // 21

// Прочие операции
nums.stream().count();                 // 6
nums.stream().anyMatch(n -> n > 5);     // true
nums.stream().sorted().findFirst().get(); // 1
String joined = nums.stream()
    .map(String::valueOf)
    .collect(Collectors.joining(", ")); // "1, 2, 3, 4, 5, 6"
Поддержать проект