Получи случайную криптовалюту за регистрацию!

Java: fill the gaps

Логотип телеграм канала @java_fillthegaps — Java: fill the gaps J
Логотип телеграм канала @java_fillthegaps — Java: fill the gaps
Адрес канала: @java_fillthegaps
Категории: Технологии
Язык: Русский
Количество подписчиков: 10.33K
Описание канала:

Привет! Меня зовут Диана, и я занимаюсь java разработкой с 2013г.
Делюсь опытом/знаниями по темам:
- Java Core
- Вопросы с собеседований
- Best practices
Комплименты, вопросы, предложения: @utki_letyat

Рейтинги и Отзывы

4.50

2 отзыва

Оценить канал java_fillthegaps и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

1

4 звезд

1

3 звезд

0

2 звезд

0

1 звезд

0


Последние сообщения 21

2021-02-10 09:01:18 Понятия в БД, часть 1. ACID

Какими свойствами обладает БД - популярный вопроc на собеседовании. Предполагается, что кандидат назовёт аббревиатуру ACID и cкажет 4 главных слова - Atomicity, Consistency, Isolation, Durability. На этих нехитрых знаниях можно дорасти до позиции сеньор, но дальше этого будет недостаточно.

Этот пост о том, зачем нужен ACID, какую задачу решает и как влияет на разработку.

ACID - это набор гарантий. Подразумевается, что если БД обозначена как ACID-compliant, можно ожидать следующее:

A - Atomicity
Можно объединить несколько операций в одну транзакцию. Если произойдёт ошибка, уже сделанные операции в группе отменятся. Всё или ничего.

Благодаря этому свойству можно не держать в коде несколько версий данных "на всякий случай" и восстанавливаться после ошибок гораздо проще.

C - Consistency
Целостность - широкий термин и его значения отличаются в ACID и CAP теореме. Что это значит в ACID: если для данных в БД заданы ограничения(constaints), то гарантируется их соблюдение всегда и везде. Если две транзакции захотят записать одинаковые значения в колонку с UNIQUE, то одна транзакция завершится с ошибкой.

Пользы от этого свойства мало. Обычно все проверки находятся в коде, поэтому у базы здесь немного работы.

I - Isolation
Каждая транзакция выполняется так, как будто других транзакций не существует.

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

Такая схема работает медленно, поэтому у БД есть менее строгие уровни изоляции. База работает быстрее, но возможны аномалии в данных. Подробно поговорим о них в части 2.

D - Durability
Если данные записаны в БД, они не потеряются. Даже если выключится свет во всём районе.

Достигается двумя способами:
Запись на носитель, например, жёсткий диск или SSD
Отправка копий на другие сервера

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

Подведём итог. ACID не даёт гарантий на уровне "записал и забыл". Целостность данных лежит на бизнес-логике, а в коде учитываются возможные ошибки неполной изоляции.

Поэтому ACID чаще встречается не в техническом описании, а в маркетинговых текстах рядом с цифровой трансформацией и дизайн-мышлением. Новые БД не берут на себя грех называться ACID-compliant, а используют более мягкую аббревиатуру BASE. Она не даёт чувства стабильности, но лучше отражает реальность.
3.0K views06:01
Открыть/Комментировать
2021-02-10 09:01:18 Когда я была беспечным джуниором, я представляла базу данных как всемогущий цилиндр, в который записываешь что угодно, а потом читаешь.
С годами стало понятно, что это обычная программа со своими сложностями и гарантиями. В цикле из трёх статей расскажу о принципах работы БД, которые пригодятся на практике. Они не относятся к конкретным БД, но помогают понять, где на БД можно положиться, а где надо подстраховаться и написать дополнительный код.

План такой:
Часть 1 - ACID
Часть 2 - Уровни изоляции транзакций
Часть 3 - CAP теорема и BASE
2.5K views06:01
Открыть/Комментировать
2021-01-29 09:00:07 Intellij IDEA: как выучить шорткаты

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

Видела, как люди распечатывают огромный список горячих клавиш и вешают рядом с монитором. Поделюсь более прогрессивными методами:

Выучить топ-15

Статистика использования IDE находится в Help → Productivity Guide. Сортируем по колонке Used, получаем часто используемые команды. В описании указаны шорткаты. Запоминаем горячие клавиши для 10-15 действий, и продуктивность заметно растёт.

Плагин Key Promoter X

Установка: File → Settings → Plugins → Key Promoter X.

При действиях с мышкой в углу всплывает подсказка-шорткат.

Здесь работает правило 80/20: шорткаты для навигации, поиска и рефакторинга покрывают большинство ежедневных задач. Их легко выучить с помощью этих двух инструментов.
5.7K views06:00
Открыть/Комментировать
2021-01-27 09:00:46 Как считается хэшкод по умолчанию?

На собеседованиях часто обсуждают методы equals и hashcode. За что отвечают, как соотносятся между собой, когда переопределять, а когда не стоит.

В этом посте разберём, как считается хэшкод под умолчанию. Практической пользы у него, конечно, нет . Цель вопроса - проверить, понимает ли человек внутреннюю работу JVM. Бывает, что ответы на стандартные вопросы знает, а как всё связано вместе - нет. Возможен такой диалог:

- Как считается хэшкод по умолчанию?
- Это адрес объекта в памяти.
- А почему так?
- Адрес каждого объекта уникален, то что надо для хэшкода.
- Сборщик мусора перемещает объекты внутри памяти. Как это влияет на значения хэшей?
- Ээээ...

Разберём вычисление хэшкода от и до. Сигнатура метода в классе Object выглядит так:
public native int hashCode();

В разных JVM реализации могут отличаться. Рассмотрим исходный код hashcode() в OpenJDK. Там 6(!) стратегий вычисления хэшкода. Стратегия задаётся опциями VM:

-XX:+UnlockExperimentalVMOptions -XX:hashCode={число}

При первом вызове результат сохраняется внутри объекта. Хэшкод для Object считается один раз и не меняется, даже если объект перемещается в памяти. Посмотрим все возможные варианты:

Стратегия по умолчанию.
Случайное число по алгоритму Xorshift RNG. Следующее значение вычисляется на основе предыдущего. Значения равномерно распределены. У каждого потока свой генератор. Синхронизации между потоками нет, поэтому алгоритм работает быстро.

-XX:hashCode=0
Случайное число по алгоритму Lehmer RNG. Генератор один на все потоки, поэтому работает медленно.

-XX:hashCode=1
Адрес объекта в памяти и немного манипуляций с битами. Работает быстро, но не даёт равномерного распределения хэш кодов.

-XX:hashCode=2
Чемпион по скорости, возвращает 1 для всех объектов:
java.lang.Object@1

Используется как отправная точка для тестов остальных стратегий.

-XX:hashCode=3
Обычная возрастающая последовательность:
java.lang.Object@a4
java.lang.Object@a5
java.lang.Object@a6

-XX:hashCode=4
Текущий адрес в памяти. Популярный, но неправильный ответ на собеседованиях. Отчасти в этом виновата документация: там адрес приводится как пример реализации.

Рейтинг стратегий по скорости:
Вернуть единицу: 184 операций за микросекунду
Вариант по умолчанию: 176 оп/мск
Адрес в памяти-1: 175 оп/мск
Адрес в памяти-2: 160 оп/мск
Растущая последовательность: 14 оп/мск
Случайное число и глобальная переменная: 10 оп/мск

Интересно, что до java 8 самая медленная опция была вариантом по умолчанию.

Резюме:
Реализация хэшкода зависит от JVM и VM-флажков.
Расчёт на основе адреса памяти не даёт равномерного распределения.
Общие переменные в маленьких методах снижают производительность в 10 раз.
В OpenJDK 6 стратегий вычисления хэшкода. По умолчанию используется генератор случайных чисел в рамках одного потока.
5.6K viewsedited  06:00
Открыть/Комментировать
2021-01-27 09:00:45 ​На основе чего вычисляется значение после @?
2.5K views06:00
Открыть/Комментировать
2021-01-19 09:01:01 Stream API: новые методы в Java 16

16 марта выйдет java 16. Новые фичи входят во вторую превью стадию перед главным релизом 2021 - java 17 LTS.

Существующие классы тоже развиваются. В java 16 в Stream API появилось 4 новых метода, которые мы и рассмотрим в этом посте.

toList()

С 25 по 27 ноября была серия постов о коллекторах (часть 1, часть 2, часть 3). Там я писала, что вместо

collect(Collectors.toList())
было бы удобно писать просто
toList()

30 ноября разработчик Oracle добавил метод toList() в класс Stream. Вряд ли он читает этот канал, но совпадение интересное

Новый метод не совсем равнозначный:
Collectors.toList() возвращает экземпляр ArrayList.
Новый метод toList() возвращает неизменяемый список.

mapMulti

Это оптизированный flatMap. Объясню суть на примере. Заказ - класс Order, товар - класс Item. Заказ состоит из нескольких товаров. Из списка заказов хотим получить список всех товаров.

orders.stream()
.flatMap(order->order.getItems().stream())
.toList();

flatMap переводит "список списков" в один список. Товары для каждого заказа превращаются в Stream, а метод flatMap объединяет эти стримы в один.

Минус: объект стрима создаётся всегда, даже для пустых списков.

mapMulti устраняет этот недостаток:

orders.stream()
.mapMulti((order, consumer) ->
order.getItems().forEach(item -> consumer.accept(item))
).toList();

Что происходит:
mapMulti принимает на вход (order, consumer):
order - элемент стрима, в нашем случае - заказ
consumer - следующий этап в стриме. Наша задача - передать этому этапу все будущие элементы. Берём у заказа товары и для каждого вызываем consumer.accept(item).

Мультимэп не знает, для каких объектов будет вызван accept, и не может вывести тип выходных элементов. Поэтому для нормальной работы тип надо указать явно:

mapMulti(…)

Когда использовать mapMulti?

Небольшое количество элементов в списках.
Например, много заказов с 1-2 товарами

Элементы легко получить без Stream API
Основная фишка mapMulti - нет промежуточных стримов. Если внутри метода создаётся стрим, то вся выгода сходит на нет.
order.getItems().stream()…

Есть три вариации метода:
IntStream mapMultiToInt
LongStream mapMultiToLong
DoubleStream mapMultiToDouble

Для них выходной тип не указывается.
3.7K views06:01
Открыть/Комментировать
2021-01-15 17:18:07 Аннотации, часть 2: как использовать

Продолжим вчерашнюю тему. Рассмотрим Retention, и когда пригодится самодельная аннотация.

@Retention определяет, на каком этапе доступна аннотация:
SOURCE - аннотация видна только во время компиляции
CLASS - доступна также в байт-коде
RUNTIME - видна всегда, даже во время работы программы

Доступность выбирается исходя из цели. Поэтому перейдём к кейсам.

Что можно сделать через аннотации?

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

Пример: @SpringBootApplication - это комбинация @Configuration, @EnableAutoConfiguration и @ComponentScan.

Генерация кода и файлов.
Происходит на этапе компиляции:
Отмечаем код аннотацией
Создаём класс-наследник от AbstractProcessor. Определяем, на какие аннотации реагировать
Вытаскиваем дополнительную информацию через .class

Deprecated d = Account.class. getAnnotation(Deprecated.class)

Делаем что-то полезное
Включаем процессор в компиляцию. В maven-compiler-plugin это секция annotationProcessors.

Для обработки подойдут аннотации с любой RetentionPolicy.

Что получаем:
Долгая компиляция
Специфичное тестирование. Пример
Сложный и запутанный код
Не тратится время на старте приложений

Этот подход используется в библиотеке Lombok, микрофреймворках Quarkus и Micronaut, в Android фреймворке Dagger.
Библиотека Dekorate на основе аннотаций создаёт манифесты для Kubernetes и OpenShift.

Статический анализ.
Алгоритм такой же - создать наследник от AbstractProcessor, добавить в процесс компиляции.

Примеры: библиотека Google Error Prone ищет в коде ошибки, Hibernate Validator проверяет, что аннотации Hibernate корректно расставлены.

Работа с байт-кодом.
Редкий случай. В байт-коде остаются аннотации с RetentionPolicy.CLASS или RUNTIME.

Создать объекты и прокси-классы.
Доступно для аннотаций с RetentionPolicy.RUNTIME.

Основа работы многих фреймворков: Spring, Hibernate, Java EE. Под работу с аннотациями в рантайме заточены многие библиотеки: Reflections, Spring. Работать с ними удобно и приятно.

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

Теперь рассмотрим анти-кейсы, для чего аннотации НЕ нужны:

Отметить код для себя или команды.
Поставить аннотацию @RefactorASAP легко, но без дальнейших действий это бесполезно. Аннотации нужно обрабатывать, и делать это автоматически.

Чтобы запомнить место в коде, используйте TODO комментарии в Intellij IDEA.

Для бизнес-логики.
Аннотации легко добавить в обход ООП и основной логики. Так можно быстро решить проблему, но долгосрочно это неудачный вариант:

Нельзя контролировать процесс целиком
Сложно писать тесты
Сложно дебажить
Внезапные сайд-эффекты

Частая ситуация на Spring проектах: на старте запускаются десятки @PostConstruct. Если в процессе возникает ошибка, то найти и исправить её непросто.

Но вообще, чем меньше вы полагаетесь на аннотации, тем лучше.
3.8K views14:18
Открыть/Комментировать
2021-01-14 09:00:40 Аннотации, часть 1: обзор

Аннотации - дополнительная информация к исходному коду. @Override, @Deprecated, @SuppressWarnings - вот это всё.

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

Создать аннотацию легко:
public @interface MyAnnotation {}

Почему ключевое слово @интерфейс, а не @аннотейшн?

Во времена java 4 аннотаций не было и для дополнительной информации классу добавляли интерфейс-маркер. В интерфейсах Cloneable, Serializable, Remote нет методов, они используются только как дополнительный признак класса.

Подход рабочий, но похож на костыль. Цель интерфейса - показать контракт класса, поэтому для маркировки кода в java 5 ввели аннотации.

Вернёмся в наши дни. Посмотрим исходный код @Deprecated:

@Retention(RUNTIME)
@Target(value={FIELD,…})
public @interface Deprecated {

String since() default "";
boolean forRemoval() default false;

}

На этом примере видно, из чего состоит аннотация:

Поля
Содержат доп. информацию. Если указать значение по умолчанию, поле становится необязательным:

@Deprecated(since="14")
// forRemoval по умолчанию false

Список внутри @Target показывает элементы, для которых работает аннотация.
В java 7 аннотации доступны для классов, методов, параметров, полей и переменных.

В java 8 аннотации действуют везде, где указан тип. Можно писать даже такое:

new @Test Account()
throws @Test IOException
implements @Test Comparable<@Test T>

Такие аннотации называются type annotations и используются в IDE и компиляторах для анализа и строгого контроля типов.

Аннотации нельзя ставить для имён переменных. Правильный ответ на вопрос перед постом - ошибка в 5 строке:
@Test String doubled
String @Test out

@Retention определяет, когда доступна аннотация и как её можно использовать. Все виды подробно рассмотрим во второй части.

@Target и @Retention- это мета аннотации, то есть аннотации для аннотаций.

Какие ещё бывают мета-аннотации:

@Documented - аннотация появится в JavaDoc
@Inherited - наследуется подклассами
@Repeatable (Java 8) - можно использовать несколько раз для одного элемента. Иногда такое приятнее читать, чем один массив:

@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")

Создать аннотацию легко, правильно применить - уже сложнее. С этим вопросом разберёмся во второй части.
4.1K views06:00
Открыть/Комментировать