Java for Beginner
870 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Раздел 9. Исключения, логирование, отладка

Глава 1. Иерархия исключений (Exceptions)

Objects.requireNonNull() – стандартная фабрика NullPointerException

Null-ссылка, введенная Тони Хоаром в 1965 году, впоследствии названная им "миллиардной ошибкой" (billion-dollar mistake), остается одним из наиболее частых источников runtime-ошибок в Java. NullPointerException занимает второе место по частоте среди всех дефектов программного обеспечения, что подчеркивает масштаб проблемы.

В Java nullability является неявной: если API не документировано явно, разработчик не может быть уверен, может ли возвращаемое значение быть null, что приводит к недопониманию и багам.

До Java 7 проверка параметров на null выполнялась через явные условия:
public void processOrder(Order order) {
if (order == null) {
throw new NullPointerException("Order cannot be null");
}
// Основная логика
}


Этот подход многословен и не предоставляет стандартизированного способа валидации. Java 7 ввела класс java.util.Objects с методом requireNonNull(), который превратил проверку null в однострочную операцию с гибкими возможностями кастомизации сообщений.


Методы requireNonNull: три перегрузки

Класс Objects предоставляет три перегруженные версии requireNonNull, каждая из которых подходит для разных сценариев:
// 1. Базовая версия без сообщения
public static <T> T requireNonNull(T obj)

// 2. Версия со статическим сообщением
public static <T> T requireNonNull(T obj, String message)

// 3. Версия с ленивым сообщением через Supplier
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier)


Все три версии возвращают переданный объект, если он не null, что позволяет использовать их inline при инициализации полей или передаче параметров. Если объект null, выбрасывается NullPointerException с соответствующим сообщением.


Базовая версия: fail-fast без лишних слов
public class OrderService {
private final OrderRepository repository;

public OrderService(OrderRepository repository) {
this.repository = Objects.requireNonNull(repository);
}
}


Здесь requireNonNull(repository) возвращает repository, если он не null, или выбрасывает NullPointerException с дефолтным сообщением. Этот паттерн идеален для конструкторов, где требуется гарантия ненулевых зависимостей, а специфичное сообщение не критично.


Версия со статическим сообщением: контекст для отладки
public void updateInventory(Inventory inventory, String warehouseId) {
Objects.requireNonNull(inventory, "Inventory object cannot be null");
Objects.requireNonNull(warehouseId, "Warehouse ID must be specified");

inventory.adjustStock(warehouseId);
}


Статическое сообщение предоставляет контекст при возникновении исключения, облегчая отладку. Однако сообщение вычисляется всегда, даже если объект не null, что незначительно, но избыточно для горячих путей выполнения.


Версия с Supplier: ленивое вычисление сообщений

Третья перегрузка принимает Supplier<String> и вычисляет сообщение только при фактической необходимости — когда объект равен null:
public void processTransaction(Transaction tx) {
Objects.requireNonNull(tx,
() -> String.format("Transaction cannot be null at %s", Instant.now()));

// Сложное форматирование выполняется только если tx == null
}


Эта версия критически важна для сценариев, где формирование сообщения требует значительных вычислений: конкатенация строк, форматирование дат, обращение к внешним ресурсам. При нормальном выполнении Supplier не вызывается, что устраняет накладные расходы.

Сравнение производительности:
// Избыточно: сообщение формируется всегда
Objects.requireNonNull(user, "User " + userId + " not found in database " + dbName);

// Эффективно: сообщение формируется только при null
Objects.requireNonNull(user,
() -> "User " + userId + " not found in database " + dbName);


В первом случае конкатенация строк выполняется при каждом вызове метода. Во втором — только при нарушении предусловия.


#Java #для_новичков #beginner #exception #requireNonNull
👍3
Когда использовать requireNonNull

Валидация параметров методов и конструкторов

Основное применение requireNonNull — проверка предусловий (preconditions) на границе метода. Это реализация принципа fail-fast: ошибка обнаруживается немедленно, предотвращая каскадные сбои и упрощая отладку. Если метод валидирует параметры upfront, он быстро завершается с четким исключением, указывающим источник проблемы.
public class PaymentProcessor {
private final PaymentGateway gateway;
private final TransactionLogger logger;

public PaymentProcessor(PaymentGateway gateway, TransactionLogger logger) {
this.gateway = Objects.requireNonNull(gateway, "PaymentGateway is required");
this.logger = Objects.requireNonNull(logger, "TransactionLogger is required");
}

public PaymentResult process(PaymentRequest request) {
Objects.requireNonNull(request, "PaymentRequest cannot be null");

gateway.authorize(request);
logger.log(request);
return new PaymentResult();
}
}


Гарантия ненулевых возвращаемых значений


requireNonNull может использоваться для защиты от непреднамеренного возврата null из методов, особенно при делегировании к внутренним компонентам:
public Customer getCustomer(String customerId) {
Customer customer = customerRepository.findById(customerId);
return Objects.requireNonNull(customer,
() -> "Customer not found for ID: " + customerId);
}


Здесь requireNonNull служит последней линией защиты: если репозиторий вернул null (что не должно происходить по контракту, но возможно из-за бага), метод выбросит NullPointerException с информативным сообщением вместо передачи null вызывающему коду.

Защита внутреннего состояния при делегировании

При реализации методов, делегирующих вызовы внутренним объектам, requireNonNull гарантирует, что поле инициализировано:
public class CachedDataProvider {
private DataProvider delegate;

public void initialize(DataProvider provider) {
this.delegate = Objects.requireNonNull(provider);
}

public Data fetchData() {
return Objects.requireNonNull(delegate, "Provider not initialized").fetch();
}
}


Вызов fetchData() до initialize() выбросит NullPointerException с понятным сообщением, вместо стандартного NPE на разыменовании null.


Документирование через Javadoc

Использование requireNonNull должно сопровождаться документированием в Javadoc. Тег @throws указывает, что метод выбрасывает NullPointerException при нарушении параметрических ограничений:
/**
* Обрабатывает платеж через указанный шлюз.
*
* @param request запрос на платеж, не может быть null
* @param gateway платежный шлюз, не может быть null
* @return результат обработки платежа
* @throws NullPointerException если request или gateway равны null
*/
public PaymentResult process(PaymentRequest request, PaymentGateway gateway) {
Objects.requireNonNull(request, "PaymentRequest is required");
Objects.requireNonNull(gateway, "PaymentGateway is required");

return gateway.process(request);
}


Для классов, где множество методов выбрасывают NullPointerException при нарушении предусловий, можно документировать это на уровне класса, избегая повторений в каждом методе.


Связь с аннотациями @NonNull

Разделение ответственности: runtime vs compile-time

Objects.requireNonNull() обеспечивает runtime-проверку: исключение возникает во время выполнения, если null передан в метод. Аннотации @NonNull (и их аналоги) предоставляют compile-time информацию о nullability, позволяя IDE и статическим анализаторам предупреждать о потенциальных проблемах до запуска программы.

Эти механизмы комплементарны, а не взаимоисключающие. Аннотации @NonNull документируют контракт и помогают инструментам, но не обеспечивают runtime-защиту. requireNonNull гарантирует защиту во время выполнения, но не предоставляет информации для статического анализа. Идеальный подход — комбинировать оба механизма.

#Java #для_новичков #beginner #exception #requireNonNull
👍3
Экосистема аннотаций nullability

В Java-экосистеме существует множество аннотаций
@NonNull из разных источников, каждая со своей семантикой и областью применения:
JSpecify (org.jspecify.annotations.NonNull) — современный стандарт, разработанный консорциумом Google, JetBrains, Spring и других. Применяется к использованию типа (type use), что позволяет различать nullability элементов массивов и generic-типов.
Spring Framework (org.springframework.lang.NonNull) — устаревшие аннотации из Spring 5, deprecated в Spring 7 в пользу JSpecify. Применялись к полям, параметрам и возвращаемым значениям.
JetBrains (org.jetbrains.annotations.NotNull) — аннотации IntelliJ IDEA, широко поддерживаемые IDE и Kotlin-компилятором.
JSR-305 (javax.annotation.Nonnull) — спецификация, больше не поддерживаемая активно, но широко распространенная в legacy-коде.
Jakarta Bean Validation (jakarta.validation.constraints.NotNull) — используется для runtime-валидации в фреймворках вроде Hibernate Validator.

JSpecify: современный стандарт

JSpecify, выпущенный в версии 1.0.0, представляет собой наиболее перспективный стандарт для null safety в Java. Он определяет три состояния nullability: unspecified (не указано), nullable (@Nullable) и non-null (@NonNull). Ключевая особенность — аннотация @NullMarked, применяемая на уровне пакета, которая устанавливает non-null как значение по умолчанию для всех типов в пакете, устраняя необходимость в явном @NonNull для каждого параметра.
// package-info.java
@NullMarked
package com.example.service;

import org.jspecify.annotations.NullMarked;


После этого все параметры, возвращаемые значения и поля в пакете считаются non-null по умолчанию. Только явно аннотированные @Nullable типы могут содержать null.
package com.example.service;

import org.jspecify.annotations.Nullable;

public class UserService {
// Не требует @NonNull — non-null по умолчанию благодаря @NullMarked
public User findById(String id) {
// ...
}

// Явно указано, что может вернуть null
public @Nullable User findByEmail(String email) {
// ...
}

// Параметр явно nullable
public void updateNickname(String id, @Nullable String nickname) {
// ...
}
}



Интеграция requireNonNull с аннотациями

Комбинированный подход использует @NonNull (или неявный non-null через @NullMarked) для документирования контракта и статического анализа, и requireNonNull для runtime-защиты:
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

@NullMarked
public class OrderService {
private final PaymentGateway gateway;

public OrderService(PaymentGateway gateway) {
// Runtime-защита: выбросит NPE с сообщением
this.gateway = Objects.requireNonNull(gateway, "PaymentGateway is required");
}

// Метод принимает non-null по умолчанию (благодаря @NullMarked)
public Order processOrder(String orderId) {
Objects.requireNonNull(orderId, "Order ID is required");
return gateway.process(orderId);
}

// Явно nullable параметр
public Order processOrderWithNotes(String orderId, @Nullable String notes) {
Objects.requireNonNull(orderId, "Order ID is required");
// notes может быть null — допустимо по контракту
return gateway.process(orderId, notes);
}
}


В этом примере:

IDE и статические анализаторы (NullAway, Checker Framework) предупреждают о попытке передать null в non-null параметры на этапе разработки
requireNonNull гарантирует защиту во время выполнения, если статический анализ был проигнорирован или null пришел из неаннотированного кода
Кастомные сообщения в requireNonNull обеспечивают контекст при runtime-ошибках


#Java #для_новичков #beginner #exception #requireNonNull
👍3
Что выведет код?

import java.util.Objects;

public class Task300426 {
public static void main(String[] args) {
String s1 = null;
String s2 = "hello";

String result = Objects.requireNonNull(
Objects.requireNonNull(s1, "first is null"),
"second is null"
);

System.out.println(result);
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
16%
hello
68%
first is null
11%
null
5%
second is null
👍2
Что такое String.format() и System.out.printf()? 🤓

Ответ:

String.format()
— статический метод, который создает отформатированную строку с использованием спецификаторов формата (например, %s для строки, %d для целых чисел, %f для дробных, %n для перевода строки).

System.out.printf() делает то же самое, но сразу выводит в консоль (аналог System.out.println(String.format(...))).

Пример: String name = "Alice"; int age = 30; String msg = String.format("Name: %s, Age: %d", name, age);.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
История технологии сегодня — 01 мая

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

Ра́дик Мартиро́сович Мартирося́н (арм. Ռադիկ Մարտիրոսի Մարտիրոսյան; 1 мая 1936, село Мадагиз, Нагорно-Карабахская АО, Азербайджанская ССР — 5 мая 2025) — советский и армянский физик, специалист по квантовой электронике, радиофизике и радиоастрономии. В Институте радиофизики и электроники АН Армянской ССР под его руководством велись фундаментальные и прикладные исследования в области высокотемпературной сверхпроводимости. Впервые обнаружено интенсивное квази-монохроматическое собственное излучение в сверхвысокочастотном диапазоне в мостиковых пленочных структурах из высокотемпературного сверхпроводника.

Пи́тер Дэ́вид Лакс (венг. Lax Péter Dávid, англ. Peter David Lax; 1 мая 1926, Будапешт, Королевство Венгрия — 16 мая 2025, Манхэттен, Нью-Йорк) — американский математик, лауреат премии Вольфа (1987) и Абелевской премии (2005). Поле деятельности Лакса многогранно: в частности, в него входило изучение интегрируемых систем, ударной волны, гидродинамики. Он также внёс существенный вклад в развитие теории солитонов. С его именем связаны такие математические достижения и числовые методы как лемма Лакса — Мильграма, теорема эквивалентности Лакса, схема Лакса — Фридрихса, схема Лакса — Вендрофа, условие энтропии Лакса и теория Лакса — Левермора, уравнение Лакса.


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

1006 — вспыхнула сверхновая звезда SN 1006.

1930 – опубликовано имя открытой 18 февраля девятой планеты Солнечной системы — Плутон.



#Biography #Birth_Date #Events #01мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #032]

Тема: Arrays.asList() возвращает список фиксированного размера.

Проблема: Метод Arrays.asList(T... a) возвращает не java.util.ArrayList, а внутренний статический класс Arrays.ArrayList, который не реализует операции изменения размера.

Этот список является представлением (view) переданного массива. Попытка вызвать add(), remove(), clear() или другие методы, изменяющие размер, выбрасывает UnsupportedOperationException. Даже метод clear(), который кажется безопасным, выбрасывает исключение.

Решение: Если нужен изменяемый список, создайте новый ArrayList на основе результата Arrays.asList(): new ArrayList<>(Arrays.asList(с)).

Начиная с Java 9, можно использовать List.of() для неизменяемых списков (еще более строгие ограничения) или List.copyOf(). Если массив уже существует, и нужно его изменяемое представление, используйте цикл или Stream API. Помните, что изменения существующих элементов через set() работают и отражаются на исходном массиве.

public class ArraysAsListExample {

public static void main(String[] args) {
String[] colorsArray = {"Red", "Green", "Blue"};

//Антипаттерн: модификация списка из Arrays.asList()
List<String> fixedList = Arrays.asList(colorsArray);
System.out.println("Fixed list: " + fixedList); // [Red, Green, Blue]

try {
fixedList.add("Yellow"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot add: " + e);
}

try {
fixedList.remove(0); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot remove: " + e);
}

try {
fixedList.clear(); // Тоже UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot clear: " + e);
}

//Можно изменять существующие элементы
fixedList.set(0, "Cyan");
System.out.println("After set: " + fixedList); // [Cyan, Green, Blue]
// Обратите внимание: исходный массив тоже изменился!
System.out.println("Original array: " + Arrays.toString(colorsArray)); // [Cyan, Green, Blue]

//Решение 1: копирование в новый ArrayList
List<String> mutableList = new ArrayList<>(Arrays.asList(colorsArray));
mutableList.add("Yellow");
mutableList.remove(0);
System.out.println("Mutable list: " + mutableList);

//Решение 2: Java 8+ Stream для примитивов
List<Integer> numbers = Arrays.stream(new int[]{1, 2, 3})
.boxed()
.collect(Collectors.toList());
numbers.add(4);
System.out.println("From stream: " + numbers);

//Решение 3: Java 9+ неизменяемые списки
List<String> immutable = List.of("A", "B", "C");
// immutable.add("D"); // UnsupportedOperationException
// immutable.set(0, "Z"); // Также выбрасывает исключение!

//Решение 4: явное создание ArrayList с инициализацией
List<String> explicit = new ArrayList<>();
explicit.add("X");
explicit.add("Y");
explicit.add("Z");
}


Объяснение: Arrays.asList() предназначен для быстрого создания оболочки вокруг массива для использования в API, требующих Collection. Возвращаемый объект хранит ссылку на исходный массив и не поддерживает изменение размера, так как массив имеет фиксированную длину. Методы add, remove, clear не переопределены и наследуются от AbstractList, где по умолчанию выбрасывают UnsupportedOperationException.

При этом метод set() переопределен и работает корректно, изменяя соответствующий элемент в массиве. Важно помнить, что изменения в списке видны в исходном массиве, и наоборот. Начиная с Java 8, для примитивных массивов удобнее использовать стримы с boxed(). Java 9 ввел List.of(), который создает полностью неизменяемые списки (даже set() не работает), что лучше для констант.


#Java #советы
👍6
Что выведет код?

import java.util.Arrays;
import java.util.List;

public class Task010526 {
public static void main(String[] args) {
List<String> list = Arrays.asList("A", "B", "C");
String[] array = {"X", "Y", "Z"};
List<String> list2 = Arrays.asList(array);

list.set(1, "B2");
array[2] = "Z2";

System.out.print(list.get(1) + " ");
System.out.print(list2.get(2) + " ");

try {
list.add("D");
} catch (Exception e) {
System.out.print("Exception1 ");
}

try {
list2.remove(0);
} catch (Exception e) {
System.out.print("Exception2");
}
}
}


#Tasks
👍2
Что такое Date и Calendar? Какие есть альтернативы? 🤓

Ответ:

java.util.Date
— представляет момент времени (миллисекунды с 1970-01-01). Многие методы устарели.

java.util.Calendar — абстрактный класс для работы с датами и временем (получение компонентов: год, месяц, день и т.д.).

Оба имеют проблемы: мутабельность, неинтуитивные индексы месяцев (0-11), неудобство.

Начиная с Java 8, появился новый пакет java.time (LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Duration, Period) — immutable, потокобезопасный, интуитивный.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Всем привет! ✌️

Так как неожиданно для меня самого у меня стало много свободного времени, наберу желающих изучить Java.

Золотых гор не обещаю, но на Junior+/ middle вытяну однозначно.

Моя экспертиза по видео и каналу, наверняка понятна.

Пишите в лс @Oleborn
🔥7👍1
История технологии сегодня — 02 мая

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

Сю Такуми (яп. 巧 舟 Такуми Сю:) (род. май 1971, Сайтама)японский сценарист и геймдизайнер. Наиболее известен своей работой над серией игр Ace Attorney. Также он был сценаристом игры Ghost Trick: Phantom Detective, вышедшей в 2010 году.


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

Не нашел((


#Biography #Birth_Date #Events #02мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Обновление devforge.ru

Обновил визуал страниц, добавил боковую панель, удобные иконки и ссылки.

По мне - так стало заебумба 💃

Оцените?
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1🤯1🍾1