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
Что такое package в Java? Зачем они нужны? 🤓

Ответ:

package
— это механизм группировки классов и интерфейсов.

Назначение:

1) избежание конфликтов имен (классы с одинаковым именем могут существовать в разных пакетах).
2) управление доступом (модификатор default виден внутри пакета).
3) логическая структуризация проекта. Соглашение об именах: используется перевернутое доменное имя компании (например, com.company.project.module).

Физически пакет соответствует структуре директорий.


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

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

Дми́трий Бори́сович Зими́н (28 апреля 1933, Москва, РСФСР, СССР — 22 декабря 2021, Швейцария) — российский предприниматель, основатель и почётный президент компании «Вымпел-Коммуникации» (торговая марка — «Билайн»), учёный-радиотехник, доктор технических наук.

И́ан Э́шли Мёрдок (англ. Ian Ashley Murdock; 28 апреля 1973, Констанц — 28 декабря 2015, Сан-Франциско, Калифорния)основатель проекта Debian и коммерческого дистрибутива Progeny Debian.

Курт Фри́дрих Гёдель (нем. Kurt Friedrich Gödel; 28 апреля 1906, Брюнн, Австро-Венгрия — 14 января 1978, Принстон, Нью-Джерси)австрийский логик, математик и философ математики. Наиболее известен сформулированными и доказанными им теоремами о неполноте, которые оказали огромное влияние на представление об основаниях математики. Считается одним из наиболее выдающихся мыслителей XX века.

Никола́й Алекса́ндрович А́стров (1906—1992)советский инженер-конструктор бронетехники. На военной службе с 1945 года. Герой Социалистического Труда (1976). До ухода на пенсию в 1985 году в должности главного конструктора ММЗ возглавлял разработку авиадесантных самоходных установок АСУ-57 и АСУ-85, самоходной установки ЗСУ-23-4 зенитного артиллерийского комплекса «Шилка», артиллерийского тягача АТП, шасси под зенитные ракетные комплексы «Куб», «Бук», «Тор» и «Тунгуска».

Ферру́ччо Ламборги́ни (итал. Ferruccio Lamborghini; 28 апреля 1916 года, Ченто, Феррара, Италия — 20 февраля 1993 года, Перуджа, Италия)итальянский промышленник и бизнесмен, основатель Lamborghini Trattori, Automobili Lamborghini и ещё ряда компаний.


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

2001 — полёт первого космического туриста — американца Денниса Тито.


#Biography #Birth_Date #Events #28апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 9. Исключения, логирование, отладка

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

Исключения в лямбдах, Stream API, конструкторах и статических блоках

Java предоставляет единый механизм исключений на базе класса Throwable, но поведение этого механизма существенно различается в зависимости от контекста выполнения. Лямбда-выражения и Stream API, появившиеся в Java 8, наложили архитектурные ограничения на использование checked-исключений, требуя от разработчиков поиска обходных стратегий. Конструкторы и статические блоки инициализации представляют собой особые точки жизненного цикла класса, где исключения ведут себя нестандартно и требуют специфического подхода к управлению ресурсами и обработке ошибок.


Часть первая. Исключения в лямбдах и Stream API

Функциональные интерфейсы Java 8 — Function<T,R>, Consumer<T>, Supplier<T>, Predicate<T> и другие — объявляют свои абстрактные методы без throws. Это означает, что любой метод, выбрасывающий checked-исключение, не может быть использован напрямую как лямбда-выражение или method reference в контексте Stream API.

// Метод с checked-исключением
public String fetchUrl(String url) throws IOException {
return httpClient.fetch(url);
}

// Ошибка компиляции: unreported exception IOException
List<String> urls = List.of("http://api1.com", "http://api2.com");
List<String> results = urls.stream()
.map(this::fetchUrl) // Не компилируется
.collect(Collectors.toList());


Это ограничение не является oversight в дизайне языка, а отражает фундаментальную несовместимость checked-исключений с функциональным программированием. В функциональном стиле функции рассматриваются как значения, которые можно передавать, комбинировать и композировать. Checked-исключения нарушают эту композицию, требуя явной обработки на каждом уровне трансформации.


Стратегия первая: обёртка в try-catch внутри лямбды

Наиболее прямолинейный подход — обернуть вызов метода с checked-исключением в try-catch блок внутри лямбды и транслировать checked в unchecked:
List<String> results = urls.stream()
.map(url -> {
try {
return fetchUrl(url);
} catch (IOException e) {
throw new RuntimeException("Failed to fetch: " + url, e);
}
})
.collect(Collectors.toList());


Этот подход работает, но имеет серьезные недостатки. Во-первых, он загромождает код шаблонной обработкой исключений, разрушая лаконичность функционального стиля. Во-вторых, выброс RuntimeException из лямбды в Stream API прерывает весь конвейер — невозможно обработать ошибку для одного элемента и продолжить обработку остальных. В-третьих, исключение теряет семантику checked, и вызывающий код может не осознавать возможность сбоя.

Для сценариев, где требуется игнорировать ошибки и продолжить обработку, можно возвращать значение по умолчанию:
// Парсинг чисел из списка строк с игнорированием ошибок
List<String> rawValues = List.of("42", "invalid", "17", "3.14", "100");

List<Integer> parsedNumbers = rawValues.stream()
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
// Возвращаем null для невалидных значений
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());

// Результат: [42, 17, 100]


Здесь NumberFormatException — unchecked-исключение, но паттерн применим и к checked. Фильтрация Objects::nonNull удаляет null-значения, соответствующие ошибкам парсинга. Однако этот подход имеет побочный эффект: информация об ошибках теряется без логирования.

Улучшенная версия с логированием:
List<Integer> parsedNumbers = rawValues.stream()
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
logger.warn("Failed to parse integer from '{}'", s);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());



#Java #для_новичков #beginner #exception
👍2
Стратегия вторая: кастомный функциональный интерфейс с throws

Для сохранения семантики checked-исключений и повторного использования обработки можно создать собственные функциональные интерфейсы, объявляющие throws:
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}

@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}

@FunctionalInterface
public interface ThrowingSupplier<T, E extends Exception> {
T get() throws E;
}
Эти интерфейсы позволяют объявлять методы, принимающие функциональные объекты с checked-исключениями:
java
Copy
public <T, R, E extends Exception> List<R> mapWithException(
List<T> list,
ThrowingFunction<T, R, E> function) throws E {

List<R> result = new ArrayList<>();
for (T item : list) {
result.add(function.apply(item));
}
return result;
}

// Использование
List<String> urls = List.of("http://api1.com", "http://api2.com");
try {
List<String> contents = mapWithException(urls, this::fetchUrl);
} catch (IOException e) {
// Обработка ошибки
}


Однако эти интерфейсы несовместимы со стандартным Stream API. Для интеграции требуется обёртка, транслирующая кастомный интерфейс в стандартный:
public static <T, E extends Exception> Consumer<T> throwingConsumerWrapper(
ThrowingConsumer<T, E> throwingConsumer) {

return item -> {
try {
throwingConsumer.accept(item);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}

// Использование
urls.forEach(throwingConsumerWrapper(url -> {
writeToFile(url); // Метод, объявляющий throws IOException
}));


Этот подход сохраняет чистоту вызова, но по-прежнему теряет checked-семантику на границе обёртки.


#Java #для_новичков #beginner #exception
👍2
Стратегия третья: sneaky throws

Sneaky throws — техника, позволяющая выбросить checked-исключение без объявления его в сигнатуре метода, используя особенности generics и стирания типов в Java:
@SuppressWarnings("unchecked")
public static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
throw (E) e;
}

// Использование в лямбде
List<String> results = urls.stream()
.map(url -> {
try {
return fetchUrl(url);
} catch (IOException e) {
sneakyThrow(e); // Компилятор не требует throws
return null; // Недостижимый код, необходим для компиляции
}
})
.collect(Collectors.toList());


Механизм работает благодаря стиранию типов: компилятор не может проверить, что E не является RuntimeException, поэтому разрешает выброс без throws. Однако это крайне опасная практика. Вызывающий код не знает о возможности checked-исключения и не обрабатывает его. JVM вынуждена обрабатывать исключение как unchecked, что нарушает контракт типов и может привести к непредсказуемому поведению при межпроцессном взаимодействии или сериализации.

Sneaky throws оправдан только в крайне специфических сценариях: библиотечный код, полностью контролирующий контекст выполнения, или временный рефакторинг legacy-систем. В production-коде этот паттерн следует избегать.


Стратегия четвертая: Either и Try из функциональных библиотек


Наиболее элегантный подход для функциональной обработки ошибок — использование типов-результатов из библиотек вроде Vavr или самостоятельная реализация. Вместо выброса исключений метод возвращает объект, явно моделирующий два состояния: успех или ошибку.
// Упрощенная реализация Either (левая сторона — ошибка, правая — успех)
public class Either<L, R> {
private final L left;
private final R right;
private final boolean isLeft;

private Either(L left, R right, boolean isLeft) {
this.left = left;
this.right = right;
this.isLeft = isLeft;
}

public static <L, R> Either<L, R> left(L value) {
return new Either<>(value, null, true);
}

public static <L, R> Either<L, R> right(R value) {
return new Either<>(null, value, false);
}

public boolean isLeft() { return isLeft; }
public boolean isRight() { return !isLeft; }
public L getLeft() { return left; }
public R getRight() { return right; }
}


Применение для парсинга с сохранением ошибок:
public Either<String, Integer> parseInteger(String input) {
try {
return Either.right(Integer.parseInt(input));
} catch (NumberFormatException e) {
return Either.left("Invalid number format: " + input);
}
}

// Обработка в Stream API
List<String> rawValues = List.of("42", "invalid", "17", "not_a_number", "100");

List<Either<String, Integer>> results = rawValues.stream()
.map(this::parseInteger)
.collect(Collectors.toList());

List<Integer> successes = results.stream()
.filter(Either::isRight)
.map(Either::getRight)
.collect(Collectors.toList());

List<String> failures = results.stream()
.filter(Either::isLeft)
.map(Either::getLeft)
.collect(Collectors.toList());


Этот подход полностью устраняет исключения из потока управления, превращая их в значения. Клиентский код вынужден обрабатывать оба случая, что устраняет риск "забытого catch". Библиотека Vavr предоставляет готовую реализацию io.vavr.control.Either и io.vavr.control.Try с богатым API для композиции и обработки результатов.


#Java #для_новичков #beginner #exception
👍2
Практический пример: парсинг чисел с игнорированием ошибок

Объединим подходы в комплексном примере. Задача: преобразовать список строк в список целых чисел, игнорируя невалидные значения и логируя ошибки.
public class NumberParser {
private static final Logger logger = LoggerFactory.getLogger(NumberParser.class);

// Стратегия: обёртка с возвратом Optional
public List<Integer> parseAllIgnoringErrors(List<String> inputs) {
return inputs.stream()
.map(this::safeParse)
.flatMap(Optional::stream) // Java 9+: фильтрация пустых Optional
.collect(Collectors.toList());
}

private Optional<Integer> safeParse(String input) {
try {
return Optional.of(Integer.parseInt(input.trim()));
} catch (NumberFormatException e) {
logger.warn("Skipping invalid number: '{}'", input);
return Optional.empty();
}
}

// Стратегия: разделение на успешные и неуспешные
public ParseResult parseAllWithDetails(List<String> inputs) {
Map<Boolean, List<Either<String, Integer>>> partitioned = inputs.stream()
.map(this::parseWithError)
.collect(Collectors.partitioningBy(Either::isRight));

List<Integer> numbers = partitioned.get(true).stream()
.map(Either::getRight)
.collect(Collectors.toList());

List<String> errors = partitioned.get(false).stream()
.map(Either::getLeft)
.collect(Collectors.toList());

return new ParseResult(numbers, errors);
}

private Either<String, Integer> parseWithError(String input) {
try {
return Either.right(Integer.parseInt(input.trim()));
} catch (NumberFormatException e) {
return Either.left(input);
}
}

public record ParseResult(List<Integer> numbers, List<String> failedInputs) {}
}



Первый метод parseAllIgnoringErrors использует Optional для фильтрации ошибок — подход, нативно поддерживаемый Java. Второй метод parseAllWithDetails сохраняет информацию о неудачах для последующего анализа или отчетности.


Часть вторая. Исключения в конструкторах и статических блоках

Конструктор в Java — это специальный метод, вызываемый при создании объекта оператором new. Если конструктор выбрасывает исключение, объект не создается. Это фундаментальное свойство имеет важное следствие: ресурсы, выделенные внутри конструктора до момента исключения, не требуют закрытия через try-finally или try-with-resources, потому что объект не существует и не будет существовать.

public class FileProcessor {
private final FileInputStream inputStream;
private final BufferedReader reader;

public FileProcessor(String path) throws FileNotFoundException {
// Если new FileInputStream выбросит исключение,
// объект FileProcessor не будет создан
this.inputStream = new FileInputStream(path);

// Эта строка выполнится только если FileInputStream создан успешно
this.reader = new BufferedReader(new InputStreamReader(inputStream));
}
}



#Java #для_новичков #beginner #exception
👍2
В этом примере, если new FileInputStream(path) выбросит FileNotFoundException, конструктор прервется, объект FileProcessor не будет инстанцирован, и reader не будет создан. Никаких утечек ресурсов не происходит, так как FileInputStream сам не был создан.

Однако если конструктор выделяет несколько ресурсов последовательно, ситуация усложняется:
public class MultiResourceProcessor {
private final Connection connection;
private final Statement statement;
private final ResultSet resultSet;

public MultiResourceProcessor(String query) throws SQLException {
this.connection = DriverManager.getConnection(DB_URL);
this.statement = connection.createStatement();
this.resultSet = statement.executeQuery(query);
}
}


Если statement.executeQuery(query) выбросит SQLException, объект MultiResourceProcessor не будет создан, но connection и statement уже были созданы и останутся незакрытыми. Это классический сценарий утечки ресурсов в конструкторе.

Решение — использование локальных переменных и try для гарантии закрытия частично созданных ресурсов:
public MultiResourceProcessor(String query) throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;

try {
conn = DriverManager.getConnection(DB_URL);
stmt = conn.createStatement();
rs = stmt.executeQuery(query);

// Все ресурсы созданы успешно — присваиваем полям
this.connection = conn;
this.statement = stmt;
this.resultSet = rs;
} catch (SQLException e) {
// Закрытие частично созданных ресурсов
if (rs != null) try { rs.close(); } catch (SQLException ignored) {}
if (stmt != null) try { stmt.close(); } catch (SQLException ignored) {}
if (conn != null) try { conn.close(); } catch (SQLException ignored) {}
throw e;
}
}



Этот паттерн гарантирует, что любые ресурсы, созданные до возникновения исключения, будут закрыты. Однако он чрезвычайно многословен. Современный подход — отказ от сложной инициализации в конструкторе и использование фабричных методов:
public class MultiResourceProcessor {
private final Connection connection;
private final Statement statement;
private final ResultSet resultSet;

private MultiResourceProcessor(Connection connection, Statement statement, ResultSet resultSet) {
this.connection = connection;
this.statement = statement;
this.resultSet = resultSet;
}

public static MultiResourceProcessor create(String query) throws SQLException {
try (Connection conn = DriverManager.getConnection(DB_URL);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {

// ResultSet не закроется при выходе из try, так как мы его возвращаем
// Это требует специальной обработки — см. ниже
return new MultiResourceProcessor(conn, stmt, rs);
}
}
}


Важное ограничение: try-with-resources закроет ресурсы при выходе из блока, поэтому возврат ResultSet из фабричного метода требует отказа от автоматического закрытия или использования специальных оберток. В большинстве случаев лучше отложить создание ресурсов до момента фактического использования, а не выполнять их в конструкторе.


#Java #для_новичков #beginner #exception
👍2
Исключения в статических блоках

Статический блок инициализации выполняется при загрузке класса JVM, до создания любых экземпляров. Если в процессе выполнения статического блока или инициализации статической переменной возникает исключение, JVM автоматически оборачивает его в ExceptionInInitializerError.
public class ConfigHolder {
private static final Map<String, String> config;

static {
config = loadConfig(); // Может выбросить RuntimeException
}

private static Map<String, String> loadConfig() {
throw new RuntimeException("Configuration file corrupted");
}
}


При первом обращении к классу ConfigHolder будет выброшено:
java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Configuration file corrupted


ExceptionInInitializerError наследует LinkageError, что сигнализирует о фатальной проблеме при загрузке класса. Ключевое следствие: класс, выбросивший ExceptionInInitializerError, помечается как неинициализированный и не может быть использован в дальнейшем . Все последующие попытки обращения к этому классу приведут к NoClassDefFoundError с причиной "initialization error".
// Первое обращение — ExceptionInInitializerError
try {
ConfigHolder holder = new ConfigHolder();
} catch (ExceptionInInitializerError e) {
// Обработка
}

// Второе обращение — NoClassDefFoundError, даже если причина устранена
try {
ConfigHolder holder = new ConfigHolder(); // Не работает!
} catch (NoClassDefFoundError e) {
// Класс навсегда непригоден
}


Это поведение делает ExceptionInInitializerError особенно опасным: одна ошибка при загрузке класса делает его непригодным на всю жизнь JVM. Перезагрузка класса возможна только через создание нового ClassLoader.
Checked-исключения напрямую запрещены в статических блоках. Компилятор отклонит код, пытающийся выбросить checked из static initializer:
public class InvalidStatic {
static {
throw new IOException("Not allowed"); // Ошибка компиляции
}
}



Для обработки checked-исключений в статических блоках применяется паттерн оборачивания в ExceptionInInitializerError:
public class SafeStaticInit {
private static final Properties props;

static {
try {
props = loadProperties();
} catch (IOException e) {
// Оборачиваем checked в ExceptionInInitializerError
throw new ExceptionInInitializerError(e);
}
}

private static Properties loadProperties() throws IOException {
Properties p = new Properties();
try (InputStream is = SafeStaticInit.class.getResourceAsStream("/config.properties")) {
if (is == null) {
throw new IOException("Config file not found");
}
p.load(is);
}
return p;
}
}


В этом примере IOException из loadProperties() перехватывается и оборачивается в ExceptionInInitializerError. Важно: если мы явно выбрасываем ExceptionInInitializerError, JVM не оборачивает его повторно — сохраняется чистый стектрейс . Если же мы обернем checked в RuntimeException, JVM дополнительно обернет его в ExceptionInInitializerError, создавая избыточную вложенность:
// Антипаттерн: избыточная вложенность
static {
try {
props = loadProperties();
} catch (IOException e) {
throw new RuntimeException(e); // JVM обернет в ExceptionInInitializerError
}
}
// Результат: ExceptionInInitializerError -> RuntimeException -> IOException



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

import java.util.stream.Stream;

@FunctionalInterface
interface ThrowingFunctionTask280426<T, R, E extends Exception> {
R apply(T t) throws E;
}

public class Task280426 {
public static void main(String[] args) {
try {
Stream.of("1", "2", "3")
.map(wrap(s -> throwsChecked(s)))
.forEach(System.out::print);
} catch (Exception e) {
System.out.print("Error");
}
}

static int throwsChecked(String s) throws Exception {
if (s.equals("2")) throw new Exception("boom");
return Integer.parseInt(s);
}

static <T, R> java.util.function.Function<T, R> wrap(ThrowingFunctionTask280426<T, R, Exception> f) {
return t -> {
try {
return f.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
17%
123
17%
12Error
50%
1Error
17%
1 Exception
👍2
Как передаются аргументы в Java: по значению или по ссылке? 🤓

Ответ:

В Java аргументы всегда передаются по значению (by value).

Для примитивов передается само значение. Для объектов передается значение ссылки на объект (копия ссылки).

Это означает, что метод не может изменить оригинальную ссылку (переназначить объект), но может изменить состояние самого переданного объекта (вызвать методы, изменяющие поля).

Поэтому часто говорят "объекты передаются по значению ссылки".


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

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

Жюль Анри́ Пуанкаре́ (фр. Jules Henri Poincaré; 29 апреля 1854, Нанси, Франция — 17 июля 1912, Париж, Франция) — французский математик, механик, физик, астроном и философ.

Среди его самых крупных достижений:
Создание топологии.
Создание качественной теории дифференциальных уравнений.
Разработка теории автоморфных функций.
Разработка новых, чрезвычайно эффективных методов небесной механики.
Создание математических основ теории относительности, а также обобщение принципа относительности на все физические явления.
Наглядная модель геометрии Лобачевского (впервые встречается у Эудженио Бельтрами).



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

1913 — эмигрировавший в США шведский инженер-электрик Гидеон Сундбек получил патент на изобретение, известное сейчас как застёжка-молния.


#Biography #Birth_Date #Events #29апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #031]

Тема: ArrayList.subList() не копирует данные, а создает view на исходный список.

Проблема: Метод subList(int fromIndex, int toIndex) возвращает не новый независимый список, а проекцию (view) исходного ArrayList.

Все операции над view отображаются на исходный список, и наоборот. Однако при структурной модификации исходного списка (добавление или удаление элементов) после создания view, последний становится некорректным. При последующей операции над sublist выбрасывается ConcurrentModificationException.

Это частая ошибка: разработчик создает sublist, затем изменяет оригинал и пытается использовать view, получая исключение. Кроме того, изменения sublist (например, clear()) неожиданно модифицируют оригинальный список, что может привести к трудноотлаживаемым багам.

Решение: Если нужен независимый список, скопируйте sublist в новую коллекцию: new ArrayList<>(list.subList(1, 5)). Если работаете с view, избегайте структурных модификаций исходного списка. Для read-only операций sublist эффективен и удобен.

public class SubListViewExample {

public static void main(String[] args) {
List<Integer> original = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));

// Создаем view на подсписок
List<Integer> sub = original.subList(2, 5);
System.out.println("Sublist (view): " + sub); // [3, 4, 5]

//Опасность 1: изменение view меняет оригинал
sub.set(0, 99);
sub.add(100);
System.out.println("Original after modifying view: " + original);
// [1, 2, 99, 4, 5, 100, 6, 7, 8] — оригинал изменился!

//Опасность 2: модификация оригинала ломает view
try {
original.add(999); // структурная модификация оригинала
sub.get(0); // ConcurrentModificationException!
} catch (ConcurrentModificationException e) {
System.out.println("View сломан: " + e);
}

// Восстановим списки для демонстрации
original = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));
sub = original.subList(2, 5);

//Решение 1: копирование для независимой работы
List<Integer> copy = new ArrayList<>(original.subList(2, 5));
copy.set(0, 999);
copy.add(1000);
System.out.println("Original unchanged: " + original); // [1, 2, 3, 4, 5, 6, 7, 8]
System.out.println("Independent copy: " + copy); // [999, 4, 5, 1000]

//Решение 2: работа только с view без трогания оригинала
List<Integer> list = new ArrayList<>(Arrays.asList(10, 20, 30, 40, 50));
List<Integer> view = list.subList(1, 4);
// Можно безопасно читать view
System.out.println("View: " + view); // [20, 30, 40]
// Можно менять элементы через set (не структурная модификация)
view.set(1, 999);
System.out.println("Original after set: " + list); // [10, 20, 999, 40, 50]
// НО нельзя добавлять/удалять из оригинала
// list.remove(0); // сломает view!

//Альтернатива: Java 8+ Stream для создания копии
List<Integer> streamCopy = original.stream().skip(2).limit(3).collect(Collectors.toList());
System.out.println("Stream copy: " + streamCopy);
}
}


Объяснение: subList() возвращает объект внутреннего класса SubList, который хранит ссылку на исходный ArrayList и смещения. Все операции делегируются исходному списку с проверкой границ. При создании SubList запоминается счетчик модификаций (modCount) оригинала. При каждой операции view сравнивает текущий modCount оригинала с запомненным. Если они различаются (оригинал был структурно изменен), выбрасывается ConcurrentModificationException.

Структурной модификацией считается изменение размера списка (add, remove, clear). Замена элементов через set() к ней не относится. Эта защита предотвращает неконсистентное состояние, когда view указывает на неправильные диапазоны.

#Java #советы
👍5
12. RabbitMQ: Полный разбор от Confirm до DLQ — всё, что нужно для надёжной очереди задач

В этом относительно коротком видео я постарался уложить теорию по RabbitMQ и короткую реализацию, которая покроет лишь минимальный сценарий.

Мы переходим от in-memory асинхронности (@Async) к настоящему брокеру сообщений — RabbitMQ.

Вы узнаете, как построить production-конвейер задач, который не теряет сообщения при падении сервиса, умеет повторять попытки, изолирует проблемные сообщения и даёт полную видимость через метрики.

Исходный код проекта на GitHub очень ждет Ваших звезд ☺️ (Вам че блин, жалко?)

Ссылка на Youtube
Ссылка на Рутьюб

Смотрите, ставьте лайки, подписывайтесь на каналы!✌️

❗️❗️❗️ Огромная просьба - если Вам понравилась моя работа, распространите эту серию по всем доступным вам местам: телеграм, discord и прочим каналам. ❗️❗️❗️

Буду крайне благодарен
🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
Что выведет код?

import java.util.*;

public class Task290426 {
public static void main(String[] args) {
List<Integer> original = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
List<Integer> sub = original.subList(1, 4);

sub.add(99);
original.add(100);

System.out.println(sub.size());
System.out.println(original.size());
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
21%
4 6
21%
4 7
11%
3 6
47%
Исключение
👍2
Что такое NPE (NullPointerException) и как его избежать? 🤓

Ответ:

NullPointerException
— это исключение, которое возникает, когда программа пытается использовать ссылку, которая не указывает ни на какой объект (равна null).

Типичные ситуации: вызов метода у null, обращение к полю, доступ к элементу массива.

Способы избежать:
1) проверка на null перед использованием (if (obj != null)).
2) использование Optional.
3) использование Objects.requireNonNull().
4) аннотации
@Nullable и @NonNull (IDE и статические анализаторы).
5) избегание возврата null (возвращайте пустую коллекцию или Optional).


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

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

Клод Э́лвуд Ше́ннон (англ. Claude Elwood Shannon; 30 апреля 1916, Петоски, Мичиган, США — 24 февраля 2001, Медфорд, Массачусетс, США) американский инженер, криптоаналитик и математик. Считается «отцом информационного века».

Является основателем теории информации, нашедшей применение в современных высокотехнологических системах связи. Предоставил фундаментальные понятия, идеи и их математические формулировки, которые в настоящее время формируют основу для современных коммуникационных технологий. В 1948 году предложил использовать слово «бит» для обозначения наименьшей единицы информации (в статье «Математическая теория связи»). Кроме того, понятие энтропии было важной особенностью теории Шеннона. Он продемонстрировал, что введённая им энтропия эквивалентна мере неопределённости информации в передаваемом сообщении. Статьи Шеннона «Математическая теория связи» и «Теория связи в секретных системах» считаются основополагающими для теории информации и криптографии. Клод Шеннон был одним из первых, кто подошёл к криптографии с научной точки зрения, он первым сформулировал её теоретические основы и ввёл в рассмотрение многие основные понятия. Шеннон внёс ключевой вклад в теорию вероятностных схем, теорию игр, теорию автоматов и теорию систем управления — области наук, входящие в понятие «кибернетика».


Иога́нн Карл Фри́дрих Га́усс (нем. Johann Carl Friedrich Gauß; 30 апреля 1777, Брауншвейг — 23 февраля 1855, Гёттинген) — немецкий математик, механик, физик, астроном и геодезист. Считается одним из величайших математиков всех времён, «королём математиков». С именем Гаусса связаны фундаментальные исследования почти во всех основных областях математики: в алгебре, теории чисел, дифференциальной и неевклидовой геометрии, математическом анализе, теории функций комплексного переменного, теории вероятностей, а также в аналитической и небесной механике, астрономии, физике и геодезии. «В каждой области глубина проникновения в материал, смелость мысли и значительность результата были поражающими.


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

1897 — физик Джозеф Томсон на лекции в Королевском институте объявил об открытии электрона.

1993 — в Женеве объявлено, что технология Всемирной паутины (World Wide Web), разработанная сотрудником Европейской лаборатории физики элементарных частиц (CERN) англичанином Тимом Бернерсом-Ли, будет для всех бесплатной.


#Biography #Birth_Date #Events #30апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Хохма дня))) Вот что отвечает нейронка о изучении 1С 😂😂😂
🤓2
Раздел 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