Уютное сообщество джавистов
2.02K subscribers
33 photos
43 links
Уютное сообщество джавистов - это хорошие материалы,задачки,
туториалы для проверки знаний и обратная связь от соратников по изучению.

@viktorreh
Download Telegram
*Вашему вниманию предлагается новая подборка Java-новостей от InfoQ: 😃
*✔️ Стал доступен билд № 31 для JDK 20 (ранний доступ)
✔️ Стал доступен билд № 5 для JDK 21 (ранний доступ)
✔️ Выпущен новый релиз Spring Framework, версии 6.0.4
и д.р.

Приятного чтения!


Читать статью
Новости Java 52

• Вышел Kotlin 1.8.0
• Java Annotated Monthly за январь
• Maven 3.8.7
• Mockito 5.0.0

Подробности: https://minijug.ru/java_news_52.html
Каждой задаче — по языку

Я вижу как минимум два способа понимать это высказывание.

Первый (назовём его горизонтальным) предполагает, что для каждой прикладной области есть наиболее подходящий язык программирования. Например, для серверной разработки — Java, для яблок — Swift, для Android — Kotlin, для фронта — TypeScript, для системщины — Си.

Второй (назовём вертикальным) делит языки на прикладные и низкоуровневые. Например, сервер — Kotlin-JVM, Android — Kotlin-JVM/Android, яблоки — Kotlin-Native, фронт — Kotlin-JVM. Написание ОС и драйверов — Rust.

Или, например, сервер и Android — Clojure, яблоки (в React-Native) и фронт — ClojureScript, Android — Clojure.

Или сервер — Haskell, Android — Haskell (NDK или Frege), iOS и фронт — PureScript.

Мне кажется, что правильный способ понимать это высказывание — второй, т. к. нет объективных причин для каждой платформы (прикладной сферы) заводить отдельный язык.
👍6👎3
Ночная задача: реализовать функцию factorial(n) -> long.
Какое решение самое простое? Компактное? Эффективное? Зрелищное?

Напишите ваши в комментах.
👍4
fun factorial(n: Int): Long =
(2..n).fold(1L, Long::times)
💩3👍2
Полраза в жизни встречал ViewModel + MutableStateFlow. Попросили объяснить, как использовать. Чем дальше в лес, тем меньше понимания, как и зачем этим вообще пользоваться и под какими веществами это придумали 🤦

Ожидание:
val vm by viewModels(factory = { MyCoolViewModel(args) })

Реальность:
val vm: MyCoolViewModel by viewModels(factoryProducer = {
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(...): T =
MyCoolViewModel(args) as T
}
})


Ожидание:
val stateSmth = savedStateHandle.getMutableStateFlow("smth", defaultSmth)

Реальность:
отрицание, гнев, торг, пост в канал, кастомный флоу.
💩4😁1
#вопросы_с_собеседований

Как можно вывести на экран уникальные квадраты чисел используя метод map()?

Для этого можно использовать Stream. Ответ на картинке.
🔥6👎1
Ссылки на методы в Java

Лямбды в Java полезны во многих направлениях. Лямбда-выражения можно использовать для более простых задач, а лямбда-утверждения — для более сложных. Лямбды могут вызывать другие методы для текущего объекта (this) и объектов, которые находятся в области видимости, таких как текущий элемент итерации и конечная локальная переменная за пределами лямбды. Лямбду всегда можно упростить, поместив код в другой метод.

Читать статью
👍2
Для чего используются ключевые слова volatile, synchronized, transient, native?

volatile вынуждает потоки отключить оптимизацию доступа и использовать единственный экземпляр переменной. Если переменная примитивного типа – этого будет достаточно для обеспечения потокобезопасности. Если же переменная является ссылкой на объект – синхронизировано будет исключительно значение этой ссылки. Все данные, содержащиеся в объекте, синхронизированы не будут!

synchronized — это зарезервированное слово позволяет добиваться синхронизации в помеченных им методах или блоках кода.

Ключевые слова
transient и native к многопоточности никакого отношения не имеют, первое используется для указания полей класса, которые не нужно сериализовать, а второе сигнализирует о том, что метод реализован в платформо-зависимом коде.

#вопросы_с_собеседований
👍11
Друзья, мы создали канал с вакансиями по Java.

В чем там фишка?
— В каждой вакансии есть ссылка на телеграм аккаунт HR-менеджера или технического специалиста этой вакансии.

Вы сразу же можете заслать в телеге ваше резюме или задать вопрос по вакансии.

Подписывайтесь и ищите работу: @javaoffers
👍1
Разбираемся, что не так с кодом в новой рубрике⬇️

Вопрос: Почему код не скомпилируется?

Ответ:
В цикле while нет условия типа Boolean
👍13
Что такое «конструктор по умолчанию»?

Если у какого-либо класса не определить конструктор, то компилятор сгенерирует конструктор без аргументов - так называемый «конструктор по умолчанию».

public class ClassName() {}

Если у класса уже определен какой-либо конструктор, то конструктор по умолчанию создан не будет и, если он необходим, его нужно описывать явно.

#вопросы_с_собеседований
👍3
Что такое Optional?

Опциональное значение Optional — это контейнер для объекта, который может содержать или не содержать значение null. Такая обёртка является удобным средством предотвращения NullPointerException, т.к. имеет некоторые функции высшего порядка, избавляющие от добавления повторяющихся if null/notNull проверок:

Optional<String> optional = Optional.of("hello");

optional.isPresent(); // true
optional.ifPresent(s -> System.out.println(s.length())); // 5
optional.get(); // "hello"
optional.orElse("ops..."); // "hello"

#вопросы_с_собеседований
👍12
Друзья, какие каналы и сайты по Java вы читаете для обучения?

Напишите в комментах под постом ☕️
🔥4
IDEA: замена кода и сто шагов назад (тихо на пальцах)

Недавно посмотрела доклад с конференции Devoxx и узнала две полезные штуки для дебага. О них и расскажу в посте.

1️⃣ Откат на предыдущий фрейм

У каждого потока есть стек вызовов. Оказывается, по нему можно перемещаться!

Чтобы сделать шаг назад, щёлкните в дебаггере область слева от метода. Внизу поста скриншот — рядом с методом должна появиться стрелка

2️⃣ Замена исполняемого кода

В дебаге нажать Shift-Shift и ввести Reload Changed Classes
или
Run → Debugging Actions → Reload Changed Classes

Нельзя заменять код в том методе, где остановился дебаггер. В любом другом — можно

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

🔸 Зайти в удалённый дебаг, найти ошибку
🔸 Вернуться на пару фреймов назад
🔸 Поправить ошибку, сделать замену класса
🔸 Проверить, что всё ок

При этом сервис продолжит работать с исправленным классом, ну разве не красота🥰
👍4🥰1🤔1
Почему нельзя использовать byte[] в качестве ключа в HashMap?

Хэш-код массива не зависит от хранимых в нем элементов, а присваивается при создании массива (метод вычисления хэш-кода массива не переопределен и вычисляется по стандартному Object.hashCode() на основании адреса массива). Так же у массивов не переопределен equals и выполняется сравнение указателей. Это приводит к тому, что обратиться к сохраненному с ключом-массивом элементу не получится при использовании другого массива такого же размера и с такими же элементами, доступ можно осуществить лишь в одном случае — при использовании той же самой ссылки на массив, что использовалась для сохранения элемента.

#вопросы_с_собеседований
👍7
Что такое effectively final и что с ним делать

Начну с правильного ответа на вопрос выше. В точке Б мы получим предупреждение компилятора: local variables referenced from a lambda expression must be final or effectively final

В этом посте обсудим, что означает effectively final, о чём молчит спецификация и как менять переменные внутри лямбд.

Про модификатор final всё понятно — он запрещает изменение переменной

final int count = 100;

count всегда будет равен 100. Каждый, кто напишет

count = 200;

будет осуждён компилятором. Для ссылок схема такая же:

final User admin = User.createAdmin();

Ссылка admin всегда будет указывать на объект User с параметрами админа. Никто не может её переприсвоить:

 admin = new User(…)

Effectively final называется переменная, значение которой не меняется после инициализации. По сути это тот же final, но без ключевого слова.

Чтобы компилятор не ругался, надо выполнить два условия:

1️⃣ Локальная переменная однозначно определена до начала лямбда-выражения

Так не скомпилируется:
int x;
if (…) х = 10

Вот так норм:
int x;
if (…) х = 10; else х = 15;

2️⃣ Переменная не меняется внутри лямбды и после неё

int х = 10;
…лямбда…
х = 15

User user = …
…лямбда…
user = userRepository.findByName(…)
user.setTIN(…)

Зачем нужно такое ограничение?

JLS 15.27.2 говорит, что ограничение помогает избежать многопоточных проблем: The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems

С первого взгляда звучит разумно. Основное применение лямбд — в рамках Stream API. В Stream API есть опция parallel(), которая запускает выполнение в разных потоках. Там и возникнут concurrency problems.

Но я не принимаю это объяснение, потому что:

🤔 С каких пор компилятор волнуют многопоточные проблемы? Вся многопоточка отдана под контроль разработчика с начала времён

🤔 Если локальная переменная станет полем класса, то компилятор перестанет ругаться. При этом вероятность concurrency problems увеличится в разы

Моя гипотеза: требование final/effectively final связано с особенностями реализации лямбд и ограничением модели памяти. Это технические сложности в JVM и ничего больше. Отсутствие многопоточных проблем, о которых говорится в JLS, это всего лишь следствие, а не причина.

Как же менять переменные внутри лямбд?

1️⃣ Сделать переменную полем класса:

int count;
public void m() {
list.forEach(v -> count++);
}

Не лучший вариант, переменная доступна теперь другим потокам. Concurrency problems!

2️⃣ Использовать Atomic обёртку

Для примитивов:
AtomicInteger count = new AtomicInteger(0);
list.forEach(v -> count.incrementAndGet())

Для ссылок:
AtomicReference<User> user = new AtomicReference<>();
…map(i -> user.set(…))

3️⃣ Использовать массив с одним элементом

int[] res = new int[] {0};
list.forEach(v -> res[0]++);

Популярный вариант, который подходит и для примитивов, и для ссылок. Но мне больше нравится вариант с Atomic:)
👍4