Проблема с неправильными источниками
Демонстрация: LinkedList vs ArrayList
Ожидаемый результат: LinkedList в 3–10 раз медленнее из-за невозможности эффективного разбиения.
Интеграция в проект «Библиотеке»
Задача: параллельный анализ большой библиотеки
Добавьте в Library метод для статистики с тяжёлыми вычислениями:
Сравните с последовательной версией на 100 000 книгах.
Практические задания
Задача 1: неправильное использование
Напишите код, который демонстрирует проблемы:
parallelStream().forEach(System.out::println) — беспорядок в выводе
parallelStream().sorted() — избыточная синхронизация
parallelStream() для записи в общий StringBuilder — race condition
Объясните, почему каждый случай ломается.
Задача 2: правильный кастомный коллектор (звёздочка)
Реализуйте parallelStream-совместимый коллектор для Map<Author, List<Book>>, который:
Использует ConcurrentHashMap для аккумулятора
Корректно обрабатывает combiner для слияния частичных результатов
Сохраняет порядок книг внутри автора
Сравните производительность с groupingByConcurrent.
#Java #для_новичков #beginner #stream_api #ForkJoinPool #parallelStream #практика
Демонстрация: LinkedList vs ArrayList
List<Book> arrayList = new ArrayList<>(largeLibrary);
List<Book> linkedList = new LinkedList<>(largeLibrary);
// ArrayList — хорошее разбиение
long arrayListParallel = measure(() ->
arrayList.parallelStream().filter(...).collect(...));
// LinkedList — плохое разбиение
long linkedListParallel = measure(() ->
linkedList.parallelStream().filter(...).collect(...));
System.out.println("ArrayList parallel: " + arrayListParallel + " мс");
System.out.println("LinkedList parallel: " + linkedListParallel + " мс");
Ожидаемый результат: LinkedList в 3–10 раз медленнее из-за невозможности эффективного разбиения.
Интеграция в проект «Библиотеке»
Задача: параллельный анализ большой библиотеки
Добавьте в Library метод для статистики с тяжёлыми вычислениями:
public Map<String, Double> analyzeGenreComplexityParallel() {
return books.parallelStream()
.collect(Collectors.groupingByConcurrent(
book -> book.getGenres().get(0), // основной жанр
Collectors.averagingInt(Book::getComplexity)
));
}Сравните с последовательной версией на 100 000 книгах.
Практические задания
Задача 1: неправильное использование
Напишите код, который демонстрирует проблемы:
parallelStream().forEach(System.out::println) — беспорядок в выводе
parallelStream().sorted() — избыточная синхронизация
parallelStream() для записи в общий StringBuilder — race condition
Объясните, почему каждый случай ломается.
Задача 2: правильный кастомный коллектор (звёздочка)
Реализуйте parallelStream-совместимый коллектор для Map<Author, List<Book>>, который:
Использует ConcurrentHashMap для аккумулятора
Корректно обрабатывает combiner для слияния частичных результатов
Сохраняет порядок книг внутри автора
Сравните производительность с groupingByConcurrent.
#Java #для_новичков #beginner #stream_api #ForkJoinPool #parallelStream #практика
👍4🔥1
Что выведет код?
#Tasks
import java.util.*;
public class Task230326 {
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>();
set.add("apple");
set.add("banana");
System.out.println(set.contains(null));
}
}
#Tasks
👍2
👍2
Что такое varargs (variable arguments)? 🤓
Ответ:
Varargs (синтаксис ...) позволяет передавать в метод произвольное количество аргументов одного типа.
Объявляется как void method(String... args). Внутри метода аргументы обрабатываются как массив.
Varargs-параметр должен быть последним в списке параметров метода.
Это удобная альтернатива передаче массива — можно вызывать метод как method("a", "b", "c"), так и method() (с пустым массивом).
#собеседование
Ответ:
Объявляется как void method(String... args). Внутри метода аргументы обрабатываются как массив.
Varargs-параметр должен быть последним в списке параметров метода.
Это удобная альтернатива передаче массива — можно вызывать метод как method("a", "b", "c"), так и method() (с пустым массивом).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологий сегодня — 24 марта
ℹ️ Кто родился в этот день
Серге́й Ива́нович Вави́лов (12 [24] марта 1891, Москва — 25 января 1951, там же) — советский физик, основатель научной школы физической оптики в СССР, общественный деятель и популяризатор науки; младший брат генетика Николая Вавилова. Президент Академии наук СССР (с 1945; действительный член с 1932), лауреат четырёх Сталинских премий. Соавтор (наряду со своими учеником Павлом Черенковым и коллегами Игорем Таммом и Ильёй Франком) открытия и истолкования эффекта Вавилова — Черенкова.
🌐 Знаковые события
1802 — английский изобретатель Ричард Тревитик получил первый патент на паровоз.
1930 — карликовая планета Плутон получает своё нынешнее имя.
2001 — выход первого релиза Mac OS X (Гепард).
#Biography #Birth_Date #Events #24марта
Серге́й Ива́нович Вави́лов (12 [24] марта 1891, Москва — 25 января 1951, там же) — советский физик, основатель научной школы физической оптики в СССР, общественный деятель и популяризатор науки; младший брат генетика Николая Вавилова. Президент Академии наук СССР (с 1945; действительный член с 1932), лауреат четырёх Сталинских премий. Соавтор (наряду со своими учеником Павлом Черенковым и коллегами Игорем Таммом и Ильёй Франком) открытия и истолкования эффекта Вавилова — Черенкова.
1802 — английский изобретатель Ричард Тревитик получил первый патент на паровоз.
1930 — карликовая планета Плутон получает своё нынешнее имя.
2001 — выход первого релиза Mac OS X (Гепард).
#Biography #Birth_Date #Events #24марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
[Совет по Java #018]
Тема: Анонимные классы и лямбды захватывают переменные. Если переменная используется внутри, она должна быть effectively final. Нельзя менять ее значение внутри лямбды.
Проблема: Лямбда-выражения и анонимные классы захватывают (capture) переменные из объемлющего контекста.
Для обеспечения согласованности и предотвращения проблем с многопоточностью Java требует, чтобы такие переменные были effectively final — то есть не изменялись после инициализации. Попытка изменить захваченную переменную внутри лямбды или передать в лямбду переменную, которая изменяется где-то еще, приводит к ошибке компиляции.
Это ограничение связано с тем, что лямбда может выполняться в другом потоке, и изменение внешней переменной создало бы состояние гонки (race condition).
Решение: Используйте обертку (массив, AtomicReference, или поле класса) для "модифицируемых" переменных, если модификация необходима.
Однако лучше пересмотреть дизайн: для накопления результатов используйте Stream API (reduce, collect) или вынесите логику в отдельный метод. Для счетчиков внутри лямбды применяйте AtomicInteger или объекты-контейнеры.
Объяснение: Понятие "effectively final" было введено в Java 8. Переменная считается effectively final, если ее значение не изменяется после инициализации.
Лямбды и анонимные классы не могут изменять локальные переменные, так как они хранятся на стеке, а лямбда может быть выполнена после выхода из метода (например, в другом потоке). Использование оберток (AtomicInteger, массивы) работает, потому что ссылка на объект-контейнер effectively final, а изменяется внутреннее состояние объекта. Однако это неидиоматично.
#Java #советы
Тема: Анонимные классы и лямбды захватывают переменные. Если переменная используется внутри, она должна быть effectively final. Нельзя менять ее значение внутри лямбды.
Проблема: Лямбда-выражения и анонимные классы захватывают (capture) переменные из объемлющего контекста.
Для обеспечения согласованности и предотвращения проблем с многопоточностью Java требует, чтобы такие переменные были effectively final — то есть не изменялись после инициализации. Попытка изменить захваченную переменную внутри лямбды или передать в лямбду переменную, которая изменяется где-то еще, приводит к ошибке компиляции.
Это ограничение связано с тем, что лямбда может выполняться в другом потоке, и изменение внешней переменной создало бы состояние гонки (race condition).
Решение: Используйте обертку (массив, AtomicReference, или поле класса) для "модифицируемых" переменных, если модификация необходима.
Однако лучше пересмотреть дизайн: для накопления результатов используйте Stream API (reduce, collect) или вынесите логику в отдельный метод. Для счетчиков внутри лямбды применяйте AtomicInteger или объекты-контейнеры.
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.*;
public class LambdaCaptureExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
//Ошибка: переменная не effectively final
int count = 0;
// names.forEach(name -> count++); // Compilation error!
//Ошибка: передача изменяемой переменной
int threshold = 5;
// threshold = 10;
// names.stream().filter(name -> name.length() > threshold); // Ошибка! threshold изменился
//Решение 1: AtomicInteger для счетчика
AtomicInteger counter = new AtomicInteger(0);
names.forEach(name -> {
if (name.length() > 3) {
counter.incrementAndGet(); // Безопасно
}
});
System.out.println("Count > 3: " + counter.get());
//Решение 2: Использование Stream API вместо накопления
long streamCount = names.stream()
.filter(name -> name.length() > 3)
.count(); // Никаких захваченных переменных
System.out.println("Stream count: " + streamCount);
//Решение 3: Массив как контейнер
int[] arrayCount = {0};
names.forEach(name -> {
if (name.length() > 3) {
arrayCount[0]++; // Работает, но менее элегантно
}
});
System.out.println("Array count: " + arrayCount[0]);
//Антипаттерн: сложный захват
for (int i = 0; i < 3; i++) {
// i меняется, нельзя использовать в лямбде
// new Thread(() -> System.out.println(i)).start(); // Ошибка!
//Правильно: копия значения
int index = i;
new Thread(() -> System.out.println("Index: " + index)).start();
}
// Пример с effectively final
String prefix = "User: "; // effectively final
names.stream()
.map(name -> prefix + name) // Работает
.forEach(System.out::println);
// prefix = "Person: "; // Раскомментируй — ошибка!
}
}
Объяснение: Понятие "effectively final" было введено в Java 8. Переменная считается effectively final, если ее значение не изменяется после инициализации.
Лямбды и анонимные классы не могут изменять локальные переменные, так как они хранятся на стеке, а лямбда может быть выполнена после выхода из метода (например, в другом потоке). Использование оберток (AtomicInteger, массивы) работает, потому что ссылка на объект-контейнер effectively final, а изменяется внутреннее состояние объекта. Однако это неидиоматично.
#Java #советы
👍6
Что выведет код?
#Tasks
import java.util.function.Consumer;
public class Task240326 {
public static void main(String[] args) {
int[] counter = {0};
Consumer<String> processor = s -> {
counter[0]++;
System.out.print(s + counter[0] + " ");
};
for (int i = 0; i < 3; i++) {
processor.accept("A");
}
System.out.println(counter[0]);
}
}
#Tasks
👍4
👍2
В чем разница между break и continue? 🤓
Ответ:
Оба оператора используются для управления потоком выполнения в циклах.
break полностью завершает выполнение цикла, в котором он находится, и передает управление на следующую за циклом инструкцию.
continue прерывает только текущую итерацию цикла и переходит к следующей итерации (проверке условия для следующего шага).
В циклах for continue выполняет инкремент/декремент, в while и do-while переходит сразу к проверке условия.
#собеседование
Ответ:
break полностью завершает выполнение цикла, в котором он находится, и передает управление на следующую за циклом инструкцию.
continue прерывает только текущую итерацию цикла и переходит к следующей итерации (проверке условия для следующего шага).
В циклах for continue выполняет инкремент/декремент, в while и do-while переходит сразу к проверке условия.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологий сегодня — 25 марта
ℹ️ Кто родился в этот день
Христофо́р Кла́виус (или Клавий, лат. Christophorus Clavius; 25 марта 1538, Бамберг — 6 февраля 1612, Рим) — немецкий математик и астроном. Член ордена иезуитов. Известен как главный разработчик окончательной версии современного григорианского календаря. В последние годы своей жизни был одним из самых уважаемых астрономов в Европе, а его книги по астрономии широко использовались более 50 лет. Множество видных европейских астрономов и математиков обучались у Клавиуса, среди них: Грегуар де Сен-Венсан, Марин Гетальдич, Джулио Алени и Пауль Гульдин.
Кейси Оуэн Нейстат (родился 25 марта 1981 г.) — американский YouTube-блогер , кинорежиссер , видеоблогер и соучредитель мультимедийной компании Beme , которая позже была приобретена CNN. В 2018 году он основал 368, креативное пространство для сотрудничества создателей.
🌐 Знаковые события
1938 — Трансляцией фильма «Великий гражданин» начато регулярное вещание Московского телецентра.
1995 — Уорд Каннингем сделал общедоступной WikiWikiWeb, первую в мире вики-систему, являющуюся частью Портлендского репозитория шаблонов.
#Biography #Birth_Date #Events #25марта
Христофо́р Кла́виус (или Клавий, лат. Christophorus Clavius; 25 марта 1538, Бамберг — 6 февраля 1612, Рим) — немецкий математик и астроном. Член ордена иезуитов. Известен как главный разработчик окончательной версии современного григорианского календаря. В последние годы своей жизни был одним из самых уважаемых астрономов в Европе, а его книги по астрономии широко использовались более 50 лет. Множество видных европейских астрономов и математиков обучались у Клавиуса, среди них: Грегуар де Сен-Венсан, Марин Гетальдич, Джулио Алени и Пауль Гульдин.
Кейси Оуэн Нейстат (родился 25 марта 1981 г.) — американский YouTube-блогер , кинорежиссер , видеоблогер и соучредитель мультимедийной компании Beme , которая позже была приобретена CNN. В 2018 году он основал 368, креативное пространство для сотрудничества создателей.
1938 — Трансляцией фильма «Великий гражданин» начато регулярное вещание Московского телецентра.
1995 — Уорд Каннингем сделал общедоступной WikiWikiWeb, первую в мире вики-систему, являющуюся частью Портлендского репозитория шаблонов.
#Biography #Birth_Date #Events #25марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 8. Stream API и функциональный стиль в Java
Глава 7: Stream API в экосистеме Java. Интеграционные паттерны
Примитивные стримы (IntStream, LongStream)
Одно из фундаментальных ограничений Java — отсутствие обобщений (generics) для примитивных типов. Stream<T> может содержать только ссылочные типы, что вынуждает упаковывать int в Integer, long в Long, double в Double. Эта операция, называемая боксингом (boxing), создаёт объекты-обёртки в куче, увеличивает нагрузку на GC и снижает производительность кэша процессора из-за разыменования указателей.
Примитивные стримы — IntStream, LongStream, DoubleStream — решают эту проблему через специализацию. Они работают с сырыми примитивами, избегая аллокаций и обеспечивая плотное размещение данных в памяти.
Генерация числовых последовательностей
range и rangeClosed
IntStream.range(start, end) генерирует последовательность от start (включительно) до end (исключительно). rangeClosed включает обе границы.
Эти методы возвращают упорядоченные, конечные потоки с известным размером — оптимальные характеристики для параллелизма. Spliterator такого потока делится идеально: середина вычисляется как (start + end) >>> 1, создавая сбалансированные сегменты.
iterate и generate
Бесконечные последовательности создаются через iterate (с заданным началом и функцией следующего элемента) или generate (с поставщиком значений).
iterate не поддерживает эффективное разделение — каждый элемент зависит от предыдущего, что делает параллелизм бесполезным. Random.ints() оптимизирован для параллельного использования через специализированный
Spliterator.
Агрегация примитивов: статистика без промежуточных объектов
Примитивные стримы предоставляют терминальные операции, возвращающие примитивные значения без боксинга:
summaryStatistics: комплексная агрегация
Для многократной статистики за один проход:
IntSummaryStatistics — mutable контейнер, накапливающий данные без промежуточных коллекций. Эффективен для больших потоков: вместо boxed().collect(summarizingInt(Integer::intValue)) используется прямая агрегация примитивов.
#Java #для_новичков #beginner #stream_api #IntStream #LongStream
Глава 7: Stream API в экосистеме Java. Интеграционные паттерны
Примитивные стримы (IntStream, LongStream)
Одно из фундаментальных ограничений Java — отсутствие обобщений (generics) для примитивных типов. Stream<T> может содержать только ссылочные типы, что вынуждает упаковывать int в Integer, long в Long, double в Double. Эта операция, называемая боксингом (boxing), создаёт объекты-обёртки в куче, увеличивает нагрузку на GC и снижает производительность кэша процессора из-за разыменования указателей.
Примитивные стримы — IntStream, LongStream, DoubleStream — решают эту проблему через специализацию. Они работают с сырыми примитивами, избегая аллокаций и обеспечивая плотное размещение данных в памяти.
Генерация числовых последовательностей
range и rangeClosed
IntStream.range(start, end) генерирует последовательность от start (включительно) до end (исключительно). rangeClosed включает обе границы.
// Индексы для обхода: 0, 1, 2, ..., 99
IntStream indices = IntStream.range(0, 100);
// Дни месяца: 1, 2, ..., 31
IntStream days = IntStream.rangeClosed(1, 31);
Эти методы возвращают упорядоченные, конечные потоки с известным размером — оптимальные характеристики для параллелизма. Spliterator такого потока делится идеально: середина вычисляется как (start + end) >>> 1, создавая сбалансированные сегменты.
iterate и generate
Бесконечные последовательности создаются через iterate (с заданным началом и функцией следующего элемента) или generate (с поставщиком значений).
// Степени двойки: 1, 2, 4, 8, ... с ограничением
IntStream powersOfTwo = IntStream.iterate(1, n -> n * 2)
.limit(20);
// Случайные числа
IntStream randomInts = new Random().ints(); // Бесконечный
IntStream limitedRandom = new Random().ints(100, 0, 1000); // 100 чисел от 0 до 999
iterate не поддерживает эффективное разделение — каждый элемент зависит от предыдущего, что делает параллелизм бесполезным. Random.ints() оптимизирован для параллельного использования через специализированный
Spliterator.
Агрегация примитивов: статистика без промежуточных объектов
Примитивные стримы предоставляют терминальные операции, возвращающие примитивные значения без боксинга:
int sum = IntStream.range(1, 101).sum(); // 5050, возвращает int
long count = LongStream.range(0, 1_000_000).count(); // 1000000L
OptionalDouble average = IntStream.of(10, 20, 30).average(); // OptionalDouble[20.0]
OptionalInt max = IntStream.of(3, 1, 4, 1, 5).max(); // OptionalInt[5]
OptionalInt, OptionalLong, OptionalDouble — примитивные версии Optional, избегающие обёртки. Методы: isPresent(), getAsInt() / getAsLong() / getAsDouble(), orElse(int), orElseGet(IntSupplier).
summaryStatistics: комплексная агрегация
Для многократной статистики за один проход:
IntSummaryStatistics stats = IntStream.of(10, 20, 30, 40, 50)
.summaryStatistics();
System.out.println(stats.getCount()); // 5
System.out.println(stats.getSum()); // 150
System.out.println(stats.getMin()); // 10
System.out.println(stats.getMax()); // 50
System.out.println(stats.getAverage()); // 30.0
IntSummaryStatistics — mutable контейнер, накапливающий данные без промежуточных коллекций. Эффективен для больших потоков: вместо boxed().collect(summarizingInt(Integer::intValue)) используется прямая агрегация примитивов.
#Java #для_новичков #beginner #stream_api #IntStream #LongStream
👍5
Преобразования между типами стримов
boxed: примитив к ссылочному
Когда нужен полноценный Stream<T> с методами объектов:
boxed() создаёт объект для каждого примитива — дорогая операция для больших потоков. Применять осознанно, когда объектная семантика необходима.
mapToObj: примитив к произвольному объекту
Более эффективный путь создания объектов из примитивов:
Обратное преобразование для агрегации:
Эти методы критичны для производительности: mapToInt(Book::pageCount).sum() вместо map(Book::pageCount).reduce(0, Integer::sum) избегает миллионов аллокаций Integer.
Сценарий: работа с индексами
Классическая задача, не имеющая прямого решения в Stream<T> — доступ к индексу элемента. Примитивные стримы предоставляют элегантный обход:
Для List с произвольным доступом это эффективно. Для LinkedList или потоков без размера — требуется промежуточная материализация:
Сценарий: статистические расчёты
Примитивные стримы оптимизированы для математической обработки:
Параллелизм примитивных стримов
IntStream.parallel(), LongStream.parallel() наследуют все особенности ForkJoinPool. Дополнительное преимущество — отсутствие boxing при слиянии результатов. sum(), average(), summaryStatistics() в параллельном режиме используют примитивные аккумуляторы, минимизируя синхронизацию.
#Java #для_новичков #beginner #stream_api #IntStream #LongStream
boxed: примитив к ссылочному
Когда нужен полноценный Stream<T> с методами объектов:
Stream<Integer> boxed = IntStream.range(0, 100).boxed();
// Применение сложных операций, недоступных для примитивов
List<String> labels = IntStream.range(0, 100)
.boxed()
.map(i -> "Item #" + i)
.collect(toList());
boxed() создаёт объект для каждого примитива — дорогая операция для больших потоков. Применять осознанно, когда объектная семантика необходима.
mapToObj: примитив к произвольному объекту
Более эффективный путь создания объектов из примитивов:
List<Book> booksByIndex = IntStream.range(0, library.size())
.mapToObj(i -> new Book("Book " + i, "Author " + i, 2000 + i))
.collect(toList());
mapToObj(IntFunction<R>) принимает функцию, создающую объект из индекса, без промежуточного boxed().
mapToInt, mapToLong, mapToDouble: объект к примитиву
Обратное преобразование для агрегации:
// Суммарное количество страниц
int totalPages = library.stream()
.mapToInt(Book::pageCount) // Book -> int
.sum();
// Средняя цена в long-центах для точности
long averagePriceCents = library.stream()
.mapToLong(b -> b.price().multiply(BigDecimal.valueOf(100)).longValue())
.average()
.orElse(0L);
Эти методы критичны для производительности: mapToInt(Book::pageCount).sum() вместо map(Book::pageCount).reduce(0, Integer::sum) избегает миллионов аллокаций Integer.
Сценарий: работа с индексами
Классическая задача, не имеющая прямого решения в Stream<T> — доступ к индексу элемента. Примитивные стримы предоставляют элегантный обход:
// Нумерация элементов с сохранением порядка
List<String> numbered = IntStream.range(0, books.size())
.mapToObj(i -> (i + 1) + ". " + books.get(i).title())
.collect(toList());
// Поиск с индексом
OptionalInt firstExpensiveIndex = IntStream.range(0, books.size())
.filter(i -> books.get(i).price().compareTo(THRESHOLD) > 0)
.findFirst(); // Возвращает индекс, не объект
Для List с произвольным доступом это эффективно. Для LinkedList или потоков без размера — требуется промежуточная материализация:
// Обобщённый подход для любого Stream
Stream<IndexedValue<Book>> withIndex = StreamUtils.zipWithIndex(books.stream());
// Или через AtomicInteger (менее элегантно, но без внешних библиотек)
AtomicInteger index = new AtomicInteger(0);
List<String> numbered = books.stream()
.map(b -> index.getAndIncrement() + ": " + b.title())
.collect(toList()); // Не параллелизуемо!
Сценарий: статистические расчёты
Примитивные стримы оптимизированы для математической обработки:
// Корреляция двух наборов данных (упрощённо)
double[] x = fetchDataX();
double[] y = fetchDataY();
double meanX = Arrays.stream(x).average().orElse(0.0);
double meanY = Arrays.stream(y).average().orElse(0.0);
double covariance = IntStream.range(0, x.length)
.mapToDouble(i -> (x[i] - meanX) * (y[i] - meanY))
.average()
.orElse(0.0);
Arrays.stream(double[]) создаёт DoubleStream без копирования массива — эффективный доступ к существующим данным.
Параллелизм примитивных стримов
IntStream.parallel(), LongStream.parallel() наследуют все особенности ForkJoinPool. Дополнительное преимущество — отсутствие boxing при слиянии результатов. sum(), average(), summaryStatistics() в параллельном режиме используют примитивные аккумуляторы, минимизируя синхронизацию.
// Эффективная параллельная агрегация
long sum = LongStream.range(0, 100_000_000)
.parallel()
.sum(); // Разделение по сегментам, локальные суммы, финальное слияние
#Java #для_новичков #beginner #stream_api #IntStream #LongStream
👍5
Что выведет код?
#Tasks
import java.util.stream.IntStream;
public class Task250326 {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
double avg = IntStream.of(arr)
.map(i -> i % 2 == 0 ? i : 0)
.average()
.orElse(0);
System.out.println(avg);
int sum = IntStream.of(arr)
.map(i -> i % 2 == 0 ? i : 0)
.sum();
System.out.println(sum);
long count = IntStream.of(arr)
.map(i -> i % 2 == 0 ? i : 0)
.count();
System.out.println(count);
}
}
#Tasks
👍2
👍3
Что такое instanceof? 🤓
Ответ:
Оператор instanceof используется для проверки, является ли объект экземпляром определенного класса, подкласса или реализует ли он определенный интерфейс.
Возвращает true или false.
Синтаксис: object instanceof Type. Если объект null, оператор всегда возвращает false (потому что null не является экземпляром ничего).
Важно для безопасного приведения типов перед выполнением операций, специфичных для конкретного класса.
#собеседование
Ответ:
Оператор instanceof
Возвращает true или false.
Синтаксис: object instanceof Type. Если объект null, оператор всегда возвращает false (потому что null не является экземпляром ничего).
Важно для безопасного приведения типов перед выполнением операций, специфичных для конкретного класса.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологий сегодня — 26 марта
ℹ️ Кто родился в этот день
Ло́уренс Э́двард «Ла́рри» Пейдж (англ. Lawrence Edward «Larry» Page; 26 марта 1973, Лансинг, штат Мичиган, США) — американский программист, разработчик и сооснователь (совместно с Сергеем Брином) поисковой системы Google. Изобретатель PageRank, самого известного алгоритма ссылочного ранжирования Google. Пейдж является главным исполнительным директором (CEO) материнской компании Google Alphabet. 4 апреля 2011 года вновь стал главным исполнительным директором компании Google, сменив на этом посту Эрика Шмидта, после своей отставки в качестве генерального директора Google в августе 2001. Он объявил о своём намерении уйти в отставку во второй раз в июле 2015 года, чтобы стать главным исполнительным директором Alphabet, на посту во главе которой будут реорганизованы активы Google. Во главе с Пейджем Alphabet стремится добиться значительных успехов в различных отраслях.
Пал Э́рдёш (венг. Erdős Pál; 26 марта 1913, Будапешт — 20 сентября 1996, Варшава) — венгерский математик, один из наиболее продуктивных математиков XX века. Работал в самых разных областях современной математики: комбинаторика, теория графов, теория чисел, математический анализ, теория приближений, теория множеств и теория вероятностей. Лауреат множества математических наград, включая премию Вольфа (1983/1984).
🌐 Знаковые события
1999 — зафиксировано появление червя «Мелисса», поразившего за короткое время сотни тысяч компьютеров во всём мире.
#Biography #Birth_Date #Events #26марта
Ло́уренс Э́двард «Ла́рри» Пейдж (англ. Lawrence Edward «Larry» Page; 26 марта 1973, Лансинг, штат Мичиган, США) — американский программист, разработчик и сооснователь (совместно с Сергеем Брином) поисковой системы Google. Изобретатель PageRank, самого известного алгоритма ссылочного ранжирования Google. Пейдж является главным исполнительным директором (CEO) материнской компании Google Alphabet. 4 апреля 2011 года вновь стал главным исполнительным директором компании Google, сменив на этом посту Эрика Шмидта, после своей отставки в качестве генерального директора Google в августе 2001. Он объявил о своём намерении уйти в отставку во второй раз в июле 2015 года, чтобы стать главным исполнительным директором Alphabet, на посту во главе которой будут реорганизованы активы Google. Во главе с Пейджем Alphabet стремится добиться значительных успехов в различных отраслях.
Пал Э́рдёш (венг. Erdős Pál; 26 марта 1913, Будапешт — 20 сентября 1996, Варшава) — венгерский математик, один из наиболее продуктивных математиков XX века. Работал в самых разных областях современной математики: комбинаторика, теория графов, теория чисел, математический анализ, теория приближений, теория множеств и теория вероятностей. Лауреат множества математических наград, включая премию Вольфа (1983/1984).
1999 — зафиксировано появление червя «Мелисса», поразившего за короткое время сотни тысяч компьютеров во всём мире.
#Biography #Birth_Date #Events #26марта
Please open Telegram to view this post
VIEW IN TELEGRAM
Wikipedia
Пейдж, Ларри
Разработчик и cооснователь поисковой системы «Google»
👍4
[Совет по Java #019]
Тема: switch по enum без обработки всех значений — бомба замедленного действия.
Проблема: Классический оператор switch на enum с блоком default или без покрытия всех значений является скрытой угрозой.
При добавлении нового элемента в enum (например, после расширения бизнес-логики) компилятор не предупредит о том, что этот новый элемент не обрабатывается в существующих switch. Код продолжит компилироваться, а во время выполнения для нового значения сработает ветка default (или вовсе ничего, что приведет к NullPointerException при попытке присвоения результата).
Это классический пример нарушения принципа открытости/закрытости, когда расширение перечисления ломает существующую логику незаметно.
Решение: Начиная с Java 14, используйте switch-выражения (включая синтаксис с ->), которые требуют исчерпывающего покрытия (exhaustiveness) для enum и sealed типов.
Компилятор проверяет, что все возможные значения обработаны, и выдает ошибку при их неполноте. Для старых версий Java можно использовать флаг компиляции -Xlint:fallthrough или включить проверку в IDE, но это менее надежно.
Альтернатива — заменить switch на полиморфизм (метод внутри enum), что полностью исключает проблему.
Объяснение: Switch-выражения в Java 14+ (стандартизированы в Java 17) являются выражением, а не оператором, и требуют исчерпывающего покрытия для enum.
Если в enum добавится новый элемент, код с switch-выражением перестанет компилироваться, заставляя разработчика явно обработать новое значение. Это пример безопасной эволюции кода.
Старый оператор switch позволяет пропустить обработку, что делает код хрупким. Полиморфный подход с абстрактным методом внутри enum еще надежнее: добавление нового элемента требует немедленной реализации метода, и IDE подсветит ошибку.
#Java #советы
Тема: switch по enum без обработки всех значений — бомба замедленного действия.
Проблема: Классический оператор switch на enum с блоком default или без покрытия всех значений является скрытой угрозой.
При добавлении нового элемента в enum (например, после расширения бизнес-логики) компилятор не предупредит о том, что этот новый элемент не обрабатывается в существующих switch. Код продолжит компилироваться, а во время выполнения для нового значения сработает ветка default (или вовсе ничего, что приведет к NullPointerException при попытке присвоения результата).
Это классический пример нарушения принципа открытости/закрытости, когда расширение перечисления ломает существующую логику незаметно.
Решение: Начиная с Java 14, используйте switch-выражения (включая синтаксис с ->), которые требуют исчерпывающего покрытия (exhaustiveness) для enum и sealed типов.
Компилятор проверяет, что все возможные значения обработаны, и выдает ошибку при их неполноте. Для старых версий Java можно использовать флаг компиляции -Xlint:fallthrough или включить проверку в IDE, но это менее надежно.
Альтернатива — заменить switch на полиморфизм (метод внутри enum), что полностью исключает проблему.
public class SwitchEnumExample {
public enum Status {
NEW, PROCESSING, COMPLETED, CANCELLED
}
//Антипаттерн: switch с default
public static String badSwitch(Status status) {
switch (status) { // Обрабатывает не все значения
case NEW:
return "Новый";
case PROCESSING:
return "В обработке";
default:
return "Завершен или отменен"; // CANCELLED попадает сюда незаметно
}
}
//Еще хуже: без default
public static String worseSwitch(Status status) {
switch (status) {
case NEW:
return "Новый";
case PROCESSING:
return "В обработке";
case COMPLETED:
return "Завершен";
// CANCELLED не обработан — при его передаче NPE (switch без результата)
}
return null;
}
//Решение 1: Switch-выражение (Java 14+)
public static String goodSwitch(Status status) {
return switch (status) {
case NEW -> "Новый";
case PROCESSING -> "В обработке";
case COMPLETED -> "Завершен";
case CANCELLED -> "Отменен";
// Компилятор проверит, что все варианты покрыты
};
}
//Решение 2: Switch-выражение с блоком
public static String goodSwitchWithBlock(Status status) {
return switch (status) {
case NEW -> "Новый";
case PROCESSING -> "В обработке";
case COMPLETED -> {
String msg = "Завершен";
yield msg; // yield вместо return в блоке
}
case CANCELLED -> "Отменен";
};
}
// Теперь добавление нового элемента enum требует переопределения метода
// — компилятор принуждает к этому
public static void main(String[] args) {
System.out.println(goodSwitch(Status.NEW));
System.out.println(goodSwitch(Status.CANCELLED));
System.out.println(StatusWithMethod.COMPLETED.getDisplayName());
// Демонстрация проблемы
System.out.println(badSwitch(Status.CANCELLED)); // "Завершен или отменен" — потеря информации
}
}Объяснение: Switch-выражения в Java 14+ (стандартизированы в Java 17) являются выражением, а не оператором, и требуют исчерпывающего покрытия для enum.
Если в enum добавится новый элемент, код с switch-выражением перестанет компилироваться, заставляя разработчика явно обработать новое значение. Это пример безопасной эволюции кода.
Старый оператор switch позволяет пропустить обработку, что делает код хрупким. Полиморфный подход с абстрактным методом внутри enum еще надежнее: добавление нового элемента требует немедленной реализации метода, и IDE подсветит ошибку.
#Java #советы
👍4
Что выведет код?
#Tasks
public class Task260326 {
enum Level {
LOW, MEDIUM, HIGH
}
public static void main(String[] args) {
Level level = Level.valueOf("HIGH");
String result = getPriority260326(level);
System.out.println(result);
}
static String getPriority260326(Level level) {
switch (level) {
case LOW:
return "Low priority";
case MEDIUM:
return "Medium priority";
}
return "Unknown";
}
}#Tasks
👍4
👍6
Что такое тернарный оператор? 🤓
Ответ:
Тернарный оператор — это сокращенная форма записи условного оператора if-else.
Имеет синтаксис: условие ? выражение1 : выражение2.
Если условие истинно, вычисляется и возвращается выражение1, иначе — выражение2. Важно, что типы выражение1 и выражение2 должны быть совместимы для присваивания. Используется для краткости, например: int max = (a > b) ? a : b;.
Не стоит злоупотреблять вложенными тернарными операторами — код становится трудночитаемым.
#собеседование
Ответ:
Тернарный оператор
Имеет синтаксис: условие ? выражение1 : выражение2.
Если условие истинно, вычисляется и возвращается выражение1, иначе — выражение2. Важно, что типы выражение1 и выражение2 должны быть совместимы для присваивания. Используется для краткости, например: int max = (a > b) ? a : b;.
Не стоит злоупотреблять вложенными тернарными операторами — код становится трудночитаемым.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5