Java for Beginner
742 subscribers
709 photos
196 videos
12 files
1.14K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Вопрос с собеседований

Что такое distinct в Stream API? 🤓

Ответ:

Метод distinct()
удаляет дубликаты из потока на основе equals() и hashCode().

Пример:
List<Integer> unique = Stream.of(1, 2, 2, 3)
.distinct()
.collect(Collectors.toList()); // [1, 2, 3]

Для параллельных потоков использует ConcurrentHashSet внутри.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🗓 История IT-технологий сегодня — 9 сентября


ℹ️ Кто родился в этот день

Де́ннис Макалистэйр Ри́тчи (Dennis MacAlistair Ritchie; 9 сентября 1941, Бронксвилл[англ.], штат Нью-Йорк, США — предположительно 8—12 октября 2011, Беркли-Хайтс, США) — американский учёный, создатель языка C и со-разработчик UNIX. Язык C по сей день широко используется для написания приложений и операционных систем, и его влияние наблюдается во многих современных языках программирования. Unix также оказал сильное влияние, основав идеи и принципы, которые сейчас являются прочно устоявшимися в вычислительной технике. Популярные операционные системы GNU/Linux и Mac OS X, а также их инструменты являются потомками работ Ритчи, и ОС Microsoft Windows также включает инструменты для совместимости с Unix и компилятор C для разработчиков.

Ави Вигдерзон (ивр. אבי ויגדרזון‎, род. 9 сентября 1956, Хайфа) — израильско-американский математик и теоретик информатики, лауреат Turing Award за вклад в теорию вычислительной сложности и алгоритмов.


🌐 Знаковые события

2001В 01:46:40 по Гринвичу часы отсчитали миллиардную секунду эры UNIX, которая началась в полночь 1 января 1970 года — именно с этого момента Unix-системы отсчитывают «внутреннее» время.


#Biography #Birth_Date #Events #09Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Основы ООП в Java

Глава 5. Абстракция

Интерфейсы. Default и static методы

Интерфейс в Java — это полностью абстрактный тип, который определяет контракт: набор методов, которые класс должен реализовать. Он описывает "что делать", но не "как". Интерфейсы идеальны для задания общего поведения для несвязанных классов, поддерживая полиморфизм без наследования состояния.

Синтаксис:
public interface InterfaceName {
// Абстрактные методы
// (с Java 8) default и static методы
}


Особенности:
Все методы в интерфейсе до Java 8 были неявно public abstract.
Классы реализуют интерфейс через implements.
Один класс может реализовать несколько интерфейсов (множественная реализация).
Нельзя создать объект интерфейса (new Interface() — ошибка).



Интерфейсы: Основы и реализация

Класс, реализующий интерфейс, обязан предоставить реализацию всех его абстрактных методов (или стать abstract).

Пример интерфейса Drawable:
public interface Drawable {
void draw(); // Неявно public abstract
}


Классы, реализующие Drawable:
public class Circle implements Drawable {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Рисую круг радиусом " + radius);
}
}

public class Square implements Drawable {
private double side;

public Square(double side) {
this.side = side;
}

@Override
public void draw() {
System.out.println("Рисую квадрат со стороной " + side);
}
}


Полиморфизм с интерфейсом:
public class Main {
public static void main(String[] args) {
Drawable[] shapes = {new Circle(5.0), new Square(4.0)};
for (Drawable shape : shapes) {
shape.draw(); // Вызывает Circle.draw() или Square.draw()
}
}
}


Вывод:
Рисую круг радиусом 5.0
Рисую квадрат со стороной 4.0


Нюанс: Drawable объединяет несвязанные классы (Circle и Square) через общий контракт.



Default методы: Добавление реализации

С Java 8 интерфейсы могут содержать default методы — методы с реализацией, которые классы наследуют, если не переопределяют. Это позволяет расширять интерфейсы без ломки существующих реализаций.

Синтаксис:
default returnType methodName(params) {
// Реализация
}


Пример с default методом:
public interface Drawable {
void draw();

default void describe() {
System.out.println("Это фигура, которую можно нарисовать.");
}
}


В Circle и Square не нужно реализовывать describe() — он наследуется.

Но можно переопределить:
public class Circle implements Drawable {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public void draw() {
System.out.println("Рисую круг радиусом " + radius);
}

@Override
public void describe() {
System.out.println("Это круг радиусом " + radius);
}
}

Вызов circle.describe(): "Это круг радиусом 5.0".
Square использует default: "Это фигура, которую можно нарисовать.".


Зачем default:
Расширение интерфейса без изменения реализующих классов.
Общий код для большинства реализаций.
Нюанс: Если два интерфейса имеют default метод с одинаковой сигнатурой, класс должен явно переопределить его.



#Java #для_новичков #beginner #Abstract #Interfaces
👍4
Static методы: Утилиты интерфейса

С Java 8 интерфейсы могут содержать static методы — методы, принадлежащие интерфейсу, а не объекту. Они не наследуются и вызываются через имя интерфейса.

Пример:
public interface Drawable {
void draw();

default void describe() {
System.out.println("Это фигура, которую можно нарисовать.");
}

static void printInfo() {
System.out.println("Интерфейс Drawable для рисования фигур.");
}
}


Вызов:
Drawable.printInfo();  // Вывод: Интерфейс Drawable для рисования фигур.

Нюанс: Circle.printInfo() — ошибка, только Drawable.printInfo().


Зачем static:
Утилитарные функции, связанные с интерфейсом.
Не требуют объекта, упрощают организацию кода.



Все нюансы интерфейсов

Множественная реализация:
Класс может implements Interface1, Interface2, ....

Нюанс: Конфликт default методов решается переопределением:

public class MyClass implements Interface1, Interface2 {
@Override
public void method() {
Interface1.super.method(); // Выбор реализации
}
}


Модификаторы:
Абстрактные методы: Неявно public abstract.
Поля: Всегда public static final (константы).
Default/static: Явно public.


Наследование интерфейсов:
Интерфейс может extends другой интерфейс: public interface AdvancedDrawable extends Drawable { ... }.

Ошибки:
Не реализован abstract метод в non-abstract классе — ошибка.
Конфликт default методов без переопределения — ошибка.
Нельзя инстанцировать интерфейс.



Default vs abstract классы:
Интерфейсы: Нет состояния, множественная реализация, default/static методы.
Abstract классы: Могут иметь состояние, конструкторы, одиночное наследование.

Java 9+: Private методы в интерфейсах для общего кода в default/static.


Как создать это в IntelliJ IDEA

Интерфейс: New → Interface → Drawable.
Implements: В классе напишите implements Drawable, IDE предложит override.
Default/static: Напишите default void describe() {} — IDE проверит синтаксис.
Тестирование: Создайте массив Drawable[] и цикл.


Полезные советы для новичков

Используйте интерфейсы для контрактов: Когда нужно поведение без состояния.
Default для совместимости: Добавляйте общую логику, но позволяйте override.
Static для утилит: Организуйте связанные функции.
Избегайте конфликтов: Переопределяйте default методы при множественной реализации.
Ресурсы: Oracle Tutorials on Interfaces.


#Java #для_новичков #beginner #Abstract #Interfaces
👍4
Что выведет код?

interface Calculator090925 {
static int multiply(int a, int b) {
return a * b;
}

default int add(int a, int b) {
return a + b;
}
}

class Math090925 implements Calculator090925 {}

public class Task090925 {
public static void main(String[] args) {
Math090925 math = new Math090925();
System.out.println(math.add(2, 3));
System.out.println(Math.multiply(2, 3));
}
}


#Tasks
👍3
Варианты ответа:
Anonymous Quiz
52%
5 и 6
8%
6 и 5
36%
Ошибка компиляции
4%
Null
👍4
Вопрос с собеседований

Что такое NumberFormatException? 🤓

Ответ:

Возникает при попытке преобразовать строку в число в неверном формате.

Пример:
Integer.parseInt("abc"); // NumberFormatException

Используйте try-catch или валидацию.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
🗓 История IT-технологий сегодня — 10 сентября


ℹ️ Кто родился в этот день

Чарльз Си́мони (англ. Charles Simonyi), при рождении Ка́рой Ши́моньи (венг. Simonyi Károly; род. 10 сентября 1948, Будапешт) — венгеро-американский разработчик и архитектор приложений (ключевая роль в разработке Microsoft Word/Excel), пионер WYSIWYG-редакторов.


🌐 Знаковые события

2008 — запуск первого циркуляционного «первого луча» Большого адронного коллайдера (LHC).


#Biography #Birth_Date #Events #10Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Production практики для Java в Docker


Управление сборкой и архитектурой


Build args (ARG vs ENV): передача параметров при сборке


- ARG — переменная, доступная только на этапе сборки образа. Не сохраняется в финальном образе.
- ENV — переменная, доступная во время выполнения контейнера. Сохраняется в образе.


Как это работает:
- При выполнении docker build --build-arg JAVA_VERSION=17 . значение JAVA_VERSION передается в Dockerfile через ARG.
- Если ARG используется в ENV, его значение копируется в образ:

  ARG JAVA_VERSION=17
ENV JAVA_VERSION=${JAVA_VERSION}
Здесь JAVA_VERSION станет частью образа и будет доступна в runtime.


Нюансы безопасности:
- Никогда не передавайте секреты через ARG без флага --secret (например, токены для приватных репозиториев):
  docker build --secret id=github,src=./github.token .


В Dockerfile:
  RUN --mount=type=secret,id=github \
git clone https://$(cat /run/secrets/github)@github.com/private/repo.git

- Почему это важно: Секреты, переданные через ARG, попадают в историю образа (видны в docker history).

Пример для Maven:
ARG MAVEN_VERSION=3.8.6
ARG USER_HOME_DIR="/root"
RUN mkdir -p /usr/share/maven && \
curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
| tar -xzC /usr/share/maven --strip-components=1

- MAVEN_VERSION используется только при загрузке Maven и не сохраняется в образе.


Multi-arch образы (ARM64 vs x86) и кросс-сборка

Образы, собранные для разных архитектур процессоров (x86_64, ARM64), чтобы запускаться на любом устройстве — от серверов до Raspberry Pi.

Как это работает:
- Docker использует QEMU для эмуляции архитектур через binfmt_misc (механизм ядра Linux).
- Buildx — расширение Docker CLI для кросс-платформенной сборки:

  docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .

- При пушинге в реестр создается manifest list — файл, описывающий образы для разных архитектур.

Нюансы:
- Эмуляция через QEMU:
- Требует установки qemu-user-static:

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

- Замедляет сборку на 20-30% из-за эмуляции.

- Сборка нативно:
- Для ARM64 используйте серверы с ARM-процессорами (AWS Graviton, Raspberry Pi).
- В CI/CD настройте параллельную сборку для каждой архитектуры.


Пример для Java:
# Сборка под ARM64 и x86_64
FROM --platform=$BUILDPLATFORM openjdk:17 AS builder
ARG TARGETARCH
RUN echo "Собираем под архитектуру: ${TARGETARCH}"
COPY . .
RUN ./mvnw package -DskipTests

- Переменная TARGETARCH автоматически устанавливается Buildx (значения: amd64, arm64).


Использование .dockerignore для ускорения сборки

Файл, исключающий ненужные директории/файлы из build context — набора данных, передаваемых Docker Daemon при сборке.

Почему это критично:
- Build context отправляется в память Docker Daemon через сокет.
- Если в контексте есть target/ (500 МБ), сборка замедлится из-за передачи данных.


Типичное содержимое .dockerignore:
.git
.gitignore
**/target/
**/*.log
**/.idea/
**/.vscode/
docker-compose.yml

Как это работает:
1. При docker build . CLI сканирует текущую директорию.
2. Файлы из .dockerignore исключаются из контекста.
3. Оставшиеся данные архивируются и отправляются в память Docker Daemon (через /var/run/docker.sock).


Нюанс:
- .dockerignore не влияет на COPY в Dockerfile. Если файл исключен из контекста, COPY завершится ошибкой.


#Java #middle #Docker #Production
👍4
Оптимизация образов: безопасность и размер

jlink: минимальная JVM под конкретное приложение

Инструмент JDK для создания настраиваемой JVM, включающей только необходимые модули (например, java.base, java.logging).

Как это работает
:

1. Анализ зависимостей через jdeps:
jdeps --print-module-deps target/myapp.jar
Вывод: java.base,java.logging,java.xml.


2. Сборка минимальной JVM:
   RUN jlink \
--add-modules java.base,java.logging,java.xml \
--output /jlinked \
--strip-debug \ — удаление отладочной информации.
--compress 2 \ — максимальное сжатие (уменьшает размер на 30%).
--no-header-files \
--no-man-pages

Результат:
- Стандартный образ OpenJDK 17 — 450 МБ.
- Образ с jlink — 120 МБ.


Нюансы:
- Некоторые библиотеки (например, Hibernate) требуют модуля jdk.unsupported.
- Проверяйте совместимость через --dry-run.



Distroless runtime образы (Google)

Образы без операционной системы, содержащие только JVM и ваше приложение. Созданы Google для минимизации attack surface.

Пример:
FROM gcr.io/distroless/java17-debian11
COPY --from=builder /app/target/myapp.jar /app.jar
ENTRYPOINT ["/app.jar"]


Как это работает:
- Distroless использует scratch (пустой образ) и добавляет только:
- Мусоросборщик (glibc или musl)
- Базовые сертификаты SSL,
- Минимальный набор библиотек для JVM
- Нет shell (/bin/sh), поэтому docker exec -it bash невозможен.


Преимущества:
- Размер образа — 80 МБ против 450 МБ у OpenJDK.
- Нулевой attack surface: нет curl, bash, apt для эксплуатации.


Отладка:
- Для диагностики используйте sidecar-контейнеры с curl или netcat.
- Логи читайте через docker logs, метрики — через /actuator/prometheus.



Non-root user: запуск Java-приложений безопасно

Запуск процесса Java не от root, чтобы ограничить ущерб при компрометации контейнера.

Как это работает:
# Создаем пользователя с UID 1001
RUN adduser --uid 1001 --disabled-password --gecos "" appuser
USER 1001
COPY --chown=1001:1001 target/myapp.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

Нюансы безопасности:
- UID/GID:
- Используйте фиксированный UID (1001), чтобы избежать конфликтов с томами.
- Если том смонтирован с правами root, пользователь 1001 не сможет писать в него.

- Capabilities:
- По умолчанию контейнер получает capabilities NET_BIND_SERVICE (привязка к портам < 1024).
- Для запуска на порту 80:

    # docker-compose.yml
app:
cap_add:
- NET_BIND_SERVICE


Критическая ошибка
:
- Если приложение требует записи в /tmp, убедитесь, что директория доступна для записи:
  RUN mkdir /app/tmp && chown 1001:1001 /app/tmp
ENV JAVA_OPTS="-Djava.io.tmpdir=/app/tmp"


#Java #middle #Docker #Debug
👍3
Минимизация attack surface (удаление ненужных слоёв)

Техники:
1. Многоступенчатая сборка (multi-stage build):
   # Stage 1: Сборка
FROM maven:3.8.6 AS builder
COPY . .
RUN mvn package

# Stage 2: Финальный образ
FROM openjdk:17-jre-slim
COPY --from=builder target/myapp.jar /app.jar

Промежуточные слои (Maven, исходники) не попадают в финальный образ.

2. Очистка кэша в том же слое:
   RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*

- Если очистка в отдельном слое, размер образа не уменьшится (слой сохранится в истории).

3. Удаление ненужных файлов:
   RUN rm -rf $JAVA_HOME/jmods/java.corba.jmod

- Некоторые модули (CORBA, RMI) не используются в современных приложениях.


Performance tuning: настройка под контейнеры

CPU/Memory ограничения (--cpus, --memory)
Как это работает:
- Docker использует cgroups v2 для ограничения ресурсов:
  docker run -m 512m --cpus=1.5 myapp

- -m 512m — лимит памяти (записывается в /sys/fs/cgroup/memory.max),
- --cpus=1.5 — лимит CPU (эквивалентно --cpu-period=100000 --cpu-quota=150000).


Нюансы для JVM:
- По умолчанию JVM не видит лимиты cgroups и выделяет память, равную объему хоста.
- Решение:
  environment:
JAVA_TOOL_OPTIONS: "-XX:MaxRAMPercentage=75.0" //указывает JVM использовать 75% от лимита cgroups.


Проверка лимитов
:
docker exec myapp cat /sys/fs/cgroup/memory.max
docker exec myapp cat /sys/fs/cgroup/cpu.max



Thread-pool tuning под контейнеры

Проблема:
- Стандартные пулы потоков (например, ForkJoinPool) используют Runtime.getRuntime().availableProcessors(),
- В контейнере это значение равно количеству CPU хоста, а не лимиту (--cpus).


Решение:
1. Для Spring Boot:
   # application.properties
spring.task.execution.pool.core-size=4
spring.task.execution.pool.max-size=8


2. Для ванильного Java:
   int availableCpus = (int) Math.min(
Runtime.getRuntime().availableProcessors(),
Double.parseDouble(System.getenv("CPU_LIMIT"))
);
ExecutorService executor = Executors.newFixedThreadPool(availableCpus * 2);


Как получить лимит CPU:
public static int getContainerCpuLimit() {
try (BufferedReader reader = new BufferedReader(
new FileReader("/sys/fs/cgroup/cpu.max"))) {
String line = reader.readLine();
String[] parts = line.split(" ");
long quota = Long.parseLong(parts[0]);
long period = Long.parseLong(parts[1]);
return (int) (quota / period); // Например, 1.5 → 1
}
}



JVM-параметры для контейнеров

Критические параметры:
environment:
JAVA_TOOL_OPTIONS: >-
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=75.0
-XX:+UseZGC
-Djava.security.egd=file:/dev/./urandom


Объяснение:
- -XX:+UseContainerSupport (включено по умолчанию в JDK 8u191+):
- Позволяет JVM читать лимиты из cgroups.
- Без него -XX:MaxRAMPercentage игнорируется.

- -XX:MaxRAMPercentage=75.0:
- Heap = 75% от лимита памяти контейнера.
- Оставшиеся 25% — для Metaspace, native-памяти, стеков потоков.

- -XX:+UseZGC:
- Низколатентный GC (макс. задержки ~1 мс).
- Альтернативы: Shenandoah (JDK 12+), G1GC (по умолчанию).

- -Djava.security.egd=file:/dev/./urandom:
- Ускоряет старт приложений, заменяя блокирующий /dev/random на неблокирующий /dev/urandom.


Проверка работы GC:
docker exec myapp jstat -gcutil 1 1000

- Столбец ZGC покажет использование памяти и паузы сборки мусора.

#Java #middle #Docker #Debug
👍4
Debug и мониторинг: production-ready диагностика

docker exec, attach к процессу

Стандартные команды:
# Стэк-трейс
docker exec myapp jstack 1 > thread_dump.txt

# Мониторинг GC
docker exec myapp jstat -gcutil 1 1000

# Heap-дамп
docker exec myapp jcmd 1 GC.heap_dump /tmp/heap.hprof

Нюансы:
- В distroless-образах нет jstack/jstat.

Решение:
- Используйте sidecar-контейнер с OpenJDK:

    debug-tools:
image: openjdk:17
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: ["jstack", "myapp"]


- Или добавьте инструменты в образ через jlink:
    RUN jlink \
--add-modules jdk.jfr,jdk.management \
--output /jlinked



JMX/JFR в контейнере

Настройка JMX:
environment:
JAVA_TOOL_OPTIONS: >-
-Dcom.sun.management.jmxremote.port=9090
-Dcom.sun.management.jmxremote.rmi.port=9090
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=myapp
ports:
- "9090:9090"


Проблемы:
- RMI-порт: JMX использует динамические порты для RMI. Чтобы зафиксировать их:
  -Dcom.sun.management.jmxremote.rmi.port=9090


- DNS-имя:
-Djava.rmi.server.hostname=myapp — имя сервиса в Docker Compose.

JFR (Java Flight Recorder):
# Запуск записи
docker exec myapp jcmd 1 JFR.start name=recording duration=60s filename=/tmp/recording.jfr

# Экспорт метрик в Prometheus
RUN jcmd 1 JFR.configure stackdepth=128


Интеграция с Prometheus/Grafana


Шаги:
1. Добавьте Micrometer в приложение:
   <dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>


2. Настройте эндпоинт:
   management.endpoints.web.exposure.include=prometheus


3. Docker Compose:
   services:
app:
ports:
- "8080:8080"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"


4. prometheus.yml:
   scrape_configs:
- job_name: 'java'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']


Ключевые метрики:
- jvm_memory_used_bytes — использование heap,
- http_server_requests_seconds_count — количество HTTP-запросов,
- jvm_gc_pause_seconds — длительность GC-пауз.


#Java #middle #Docker #Debug
👍4
Что выведет код?

public class Task100925 {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 10;
System.out.println(a[0]);
}
}


#Tasks
👍3
Варианты ответа:
Anonymous Quiz
0%
0
28%
1
62%
10
10%
Ошибка компиляции
👍4😱1
Вопрос с собеседований

Как работает throw с generics? 🤓

Ответ:

throw
может выбрасывать generic исключения, но тип стирается в runtime.

Пример:
<T extends Throwable> void throwIt(T t) throws T {
throw t;
}

Полезно для utility методов.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤯1
🗓 История IT-технологий сегодня — 11 сентября


ℹ️ Кто родился в этот день

Не нашел никого - если кого-то знаете, пишите в комментариях.


🌐 Знаковые события

1997 — Американская автоматическая межпланетная станция Mars Global Surveyor достигла Марса


#Biography #Birth_Date #Events #11Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Основы ООП в Java

Глава 6. Ключевые модификаторы ООП

final: переменные, методы, классы

Модификатор final в Java означает "окончательный" и используется для предотвращения изменений. В зависимости от контекста — переменные, методы или классы — он ограничивает возможность переопределения, изменения или наследования.

Зачем нужен final:
Неизменяемость: Защищает данные от изменений, делая код предсказуемым.
Безопасность: Предотвращает нежелательное изменение поведения в подклассах.
Оптимизация: Компилятор может оптимизировать final-элементы, зная, что они не изменятся.
Дизайн: Помогает явно указать намерения разработчика (например, класс не для наследования).



final — один из ключевых инструментов для создания robust и maintainable кода в ООП.

1. Final переменные: Неизменяемые значения
Когда переменная помечена final, ее значение нельзя изменить после инициализации. Это делает переменную константой.

Типы переменных:
Локальные: Инициализируются один раз в методе.
Поля класса: Должны быть инициализированы при объявлении, в блоке инициализации или конструкторе.
Ссылочные типы: Ссылка неизменна, но объект, на который она указывает, может меняться (если он mutable).


Пример:
public class Circle {
private final double PI = 3.14159; // Константа
private final double radius; // Поле, инициализируется в конструкторе

public Circle(double radius) {
this.radius = radius; // Инициализация final
}

public double getArea() {
final double area = PI * radius * radius; // Локальная final переменная
// area = 10; // Ошибка: нельзя изменить
return area;
}
}


Нюанс: Для final ссылки (например, final StringBuilder sb = new StringBuilder();) нельзя переназначить sb = new StringBuilder();, но можно sb.append("text");.

Практика:

Константы: Обычно static final (например, public static final double PI = 3.14159;).
Именование: Константы в верхнем регистре с подчеркиваниями (MAX_VALUE).


2. Final методы: Запрет переопределения
Когда метод помечен final, его нельзя переопределить (override) в подклассах. Это полезно, когда поведение метода должно остаться неизменным.

Пример с наследованием:
public class Animal {
public final void eat() {
System.out.println("Животное ест.");
}
}

public class Dog extends Animal {
// Ошибка, если попытаться:
// @Override
// public void eat() { System.out.println("Собака ест кости."); }
}


Зачем:
Гарантия неизменного поведения.
Безопасность: Критичные методы (например, валидация) не изменятся.
Нюанс: final не влияет на вызов метода, только на override.


3. Final классы: Запрет наследования
Когда класс помечен final, его нельзя использовать как суперкласс (extends). Это предотвращает создание подклассов.

Пример:
public final class ImmutablePoint {
private final int x;
private final int y;

public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() { return x; }
public int getY() { return y; }
}

// Ошибка:
// public class ExtendedPoint extends ImmutablePoint {}


Зачем:
Иммутабельность: Классы вроде String или Integer — final, чтобы гарантировать неизменность.
Безопасность: Например, в криптографии или конфигурации.
Дизайн: Сигнализирует, что класс завершен и не предназначен для расширения.


#Java #для_новичков #beginner #OOP #final
👍3
Все нюансы final

Переменные:
Инициализация: Должна быть до завершения конструктора (для полей) или до использования (локальные).
Blank final: final поле без начального значения, но с обязательной инициализацией в конструкторе.
Нюанс: final List<String> list = new ArrayList<>(); — можно менять содержимое list, но не саму ссылку.


Методы:
Не влияет на полиморфизм: Вызов метода работает как обычно.
Нельзя с abstract: Абстрактный метод требует override, final запрещает.
Нюанс: Используйте для методов, где логика критична (например, security checks).


Классы:
Все методы implicitly final, но это не нужно явно указывать.
Нюанс: String, Integer, Double — примеры final классов в Java.


Ошибки:

Изменение final переменной: Ошибка компиляции.
Override final метода: Ошибка компиляции.
Extends final класса: Ошибка компиляции.


Дизайн и производительность:
Final улучшает оптимизацию JIT (компилятор знает, что не будет изменений).
Избегайте чрезмерного использования: Final классы ограничивают гибкость (например, тестирование с mocking).
Константы: static final для глобальных неизменяемых значений.


Сценарии использования:
Immutable классы: Все поля final, класс final.
Utility классы: Часто final (например, java.lang.Math).
Конфигурации: Final поля для неизменяемых настроек.



Как создать это в IntelliJ IDEA

Final переменные: Объявите поле с final, IDE проверит инициализацию.
Final методы: Добавьте final перед методом, IDE предупредит о попытке override.
Final классы: Добавьте final к классу, IDE покажет ошибку при extends.
Тестирование: Создайте Main и проверьте поведение.



Полезные советы для новичков

Константы: Используйте static final для PI, MAX_VALUE и т.д.
Иммутабельность: Делайте поля final для защиты данных.
Дизайн: Final классы для завершенных реализаций, но не злоупотребляйте.
Проверяйте: Попробуйте override final метода — IDE покажет ошибку.
Ресурсы: Oracle Tutorials on Final Classes and Methods.



#Java #для_новичков #beginner #OOP #final
👍5
Что выведет код?

public class Task110925 {
public static void main(String[] args) {
final int x = 10;
final int y = getValue();

System.out.println(x + y);
}

static int getValue() {
return 20;
}
}


#Tasks
👍3
Варианты ответа?:
Anonymous Quiz
3%
0
6%
10
54%
30
37%
Ошибка компиляции
👍3