Java Geek
2.5K subscribers
256 photos
1 file
16 links
Практичные советы, лайфхаки и код для Java-разработчиков. Каждый пост — реальная польза. Учим Java на примерах.

По всем вопросам @evgenycarter
Download Telegram
Сеттеры

В Java сеттеры (setters) являются методами класса, которые используются для установки значений приватных переменных (полей) класса. Они обеспечивают механизм инкапсуляции данных, позволяя контролировать доступ к полям класса и обеспечивать безопасность данных.

👉 @java_geek
Существует ли возможность перенаправить потоки стандартного ввода/вывода?

Да, в Java есть возможность перенаправить стандартные потоки ввода/вывода. Это можно сделать с помощью класса System и его методов setIn(), setOut() и setErr().

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

👉 @java_geek
Интерфейс BlockingQueue

Интерфейс BlockingQueue используется для реализации очередей с блокировками.
Он позволяет безопасно работать с очередью из нескольких потоков.

Основные методы:
add(E e) — добавляет элемент в очередь, может выбросить исключение если очередь переполнена.
offer(E e) — добавляет элемент в очередь, возвращает false если очередь переполнена.
put(E e) — добавляет элемент в очередь, блокирует поток если очередь переполнена.
take() — извлекает и удаляет элемент из очереди, блокирует поток если очередь пуста.
poll() — извлекает и удаляет элемент из очереди, возвращает null если очередь пуста.

👉 @java_geek
Параллельные аккумуляторы

Кроме блокировок, Java Concurrent может предложить еще одну интересную функцию — параллельные аккумуляторы. LongAccumulator обновляет значение, используя предоставленную функцию. Это позволяет нам реализовать алгоритм без блокировок в ряде сценариев. Обычно это предпочтительнее чем AtomicLong, когда несколько потоков обновляют общее значение.

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

Теперь давайте создадим LongAccumulator с начальным значением 10000а затем вызовем метод accumulate() из нескольких потоков.

👉 @java_geek
Тип Optional

Тип Optional используется для представления возможности отсутствия значения. Он обертывает другой тип данных и может содержать либо значение этого типа, либо быть пустым (null).

Этот код создает Optional объект, который может содержать строку. Если строка доступна, она будет возвращена; в противном случае будет возвращено значение «Default Value».

Использование Optional способствует более чистому и безопасному коду при работе с возможно отсутствующими значениями.

👉 @java_geek
Метод Math.random()

Используется для генерации случайного числа в диапазоне от 0.0 до 1.0. Различные диапазоны могут быть достигнуты с помощью арифметики.

Выше приведен пример выбора случайного числа в диапазоне от 0 до 10.

👉 @java_geek
Класс DataOutputStream и его методы

Поток DataOutputStream позволяет записывать примитивные данные в исходный код.

Если используйте объект DataOutputStream, то у Вас есть под рукой вспомогательные методы, которые можно использовать для записи потока или для выполнения других операций над потоком.

👉 @java_geek
Получить атомное время из интернет-часов

Для получения атомного времени из интернет-часов в Java вы можете воспользоваться классом java.net.URL для выполнения HTTP-запроса к одному из сервисов времени, таким как «time.google.com». Затем вы можете обработать полученный ответ и извлечь атомное время.

Обратите внимание, что формат ответа от сервиса времени может различаться, и вам может потребоваться настроить метод parseAtomicTime для вашего конкретного сервиса. Подобные сервисы могут предоставлять атомное время в разных форматах, таких как ISO 8601 или Unix Timestamp.

👉 @java_geek
Могли бы вы придумать ситуацию, когда блок finally не будет выполнен?

— Если в блоке try вызвать метод System.exit(). Это приведет к немедленному завершению приложения, и блок finally пропускается.

— Если произойдет аварийное завершение JVM, например OutOfMemoryError. В этом случае JVM останавливается без выполнения finally.

— Если в блоке try выбрасывается исключение Error или его подклассы (например, StackOverflowError). Такие исключения обычно означают серьезную проблему, поэтому JVM не гарантирует выполнение finally.

— Если при выполнении кода в блоке try произошел deadlock. В этом случае поток зависает, и блок finally не выполняется.

— Если программа была принудительно остановлена, например, по kill -9 в Linux.

👉 @java_geek
Метод compareAndSwap()

Метод compareAndSwap() используется для атомарного обновления значения переменной.

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

В примере мы объявляем AtomicInteger count и инициализируем его значением 0. Метод increment() сначала получает текущее значение в переменную currentValue, затем в цикле do-while вызывается compareAndSet, который проверяет равно ли текущее значение count значению currentValue, если да, то устанавливает новое значение currentValue + 1, если нет (значение изменилось другим потоком), то цикл повторяется.

Таким образом гарантируется атомарное инкрементирование переменной count.

👉 @java_geek
System.nanoTime

System.nanoTime() возвращает текущее время в наносекундах.

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

В отличие от System.currentTimeMillis(), который возвращает время в миллисекундах, nanoTime() имеет более высокое разрешение и позволяет измерять очень короткие промежутки времени.

nanoTime() часто используется для:

— Замеров производительности.
— Измерения задержек в мультитрединге.
— Микробенчмаркинга.
— Определения интервалов между событиями в реальном времени.

👉 @java_geek
Как влияет модификатор static на класс/метод/поле?

Для класса — позволяет создать static-класс, экземпляры которого создавать нельзя. Используется для создания утилитных классов.

Для метода — делает метод статическим, то есть он может быть вызван без создания экземпляра класса.

Для поля — создает поле, общее для всех экземпляров класса. Статическое поле существует в единственном экземпляре для класса.

Если кратко, static позволяет создавать классы/методы/поля, связанные с классом, а не с экземпляром.
Это удобно, когда нужно реализовать утилитные классы или объекты, общие для всех экземпляров.

👉 @java_geek
Что такое Atomic types и зачем они нужны?

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

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

Atomic типы, такие как AtomicInteger, AtomicLong, AtomicBoolean и т. д., предоставляют методы для выполнения атомарных операций, таких как get(), set(), getAndSet(), compareAndSet() и т. д.

Они полезны в многопоточном программировании, когда необходимо обеспечить целостность данных при одновременном доступе к общим данным из нескольких потоков. Использование Atomic типов может помочь избежать ошибок синхронизации и улучшить производительность по сравнению с использованием блоков synchronized, так как они не требуют блокировки.

👉 @java_geek
Метод delete() класса StringBuffer

Метод delete() в классе StringBuffer используется для удаления символов из строки. Он удаляет символы из строки, на которой он был вызван.

В качестве аргумента принимает начальный индекс и конечный индекс удаляемого фрагмента и сдвигает оставшиеся символы влево, замещая удаленные.
Возвращает ссылку на текущий объект StringBuffer.

👉 @java_geek
Метод trimToSize()

Метод trimToSize() используется для оптимизации размера внутреннего массива коллекций, таких как ArrayList или HashMap.
Этот метод позволяет уменьшить размер внутреннего массива коллекции до текущего количества элементов, то есть избавиться от неиспользуемой памяти.

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

Метод trimToSize() является необязательной оптимизацией производительности и памяти. Его можно не вызывать, в этом случае внутренний массив будет занимать максимальный размер.

👉 @java_geek
StringBuffer

StringBuffer — это класс, предназначенный для работы со строками. Он позволяет создавать модифицируемые (изменяемые) строки.

В отличие от класса String, объекты StringBuffer можно изменять после их создания, используя различные методы, такие как append(), insert(), delete().
Также StringBuffer эффективнее String при частых изменениях строки, так как не создает новый объект при каждом изменении.

Класс является потокобезопасным, т. е. может использоваться в многопоточных приложениях.

Методы StringBuffer не синхронизированы, поэтому для многопоточного доступа нужно вручную синхронизировать доступ с помощью synchronized блока.

👉 @java_geek
Callable

Callable — это интерфейс из пакета java.util.concurrent, который представляет собой задачу, которую можно выполнить и получить результат, а также обработать исключение, если оно произошло во время выполнения задачи. Он аналогичен интерфейсу Runnable, но в отличие от Runnable, Callable может возвращать результат выполнения и бросать проверяемые исключения.

👉 @java_geek
Конвертируем массив в список

Arrays.asList() — это статический метод класса Arrays, который позволяет конвертировать обычный массив в список List.

— Принимает массив в качестве аргумента и возвращает объект типа List с элементами этого массива.

— Возвращаемый список имеет фиксированный размер, равный длине исходного массива. Добавлять/удалять элементы в него нельзя.

— Изменения в возвращаемом списке будут вноситься в исходный массив, т. к. список работает как «представление» массива. Метод работает для массивов примитивных и ссылочных типов.

Arrays.asList хорош для чтения элементов массива, но не для записи из-за неизменяемого размера.

👉 @java_geek
Как не допустить сериализацию?

Чтобы не допустить автоматическую сериализацию можно переопределить private методы для создания исключительной ситуации NotSerializableException.

private void writeObject(ObjectOutputStream out) throws IOException {
throw new NotSerializableException();
}

private void readObject(ObjectInputStream in) throws IOException {
throw new NotSerializableException();
}

👉 @java_geek
Как разделить строку на части?

В Java можно разделить строку на части с помощью метода split() класса String. Метод split() разбивает исходную строку на массив строк, используя заданный разделитель.

В этом примере исходная строка «Это пример строки для разделения» разбивается на части с помощью пробела в качестве разделителя. Однако, если у вас есть другой разделитель (например, запятая или точка с запятой), просто замените значение переменной delimiter на соответствующий разделитель в вашем случае.

👉 @java_geek
CyclicBarrier

CyclicBarrier (циклический барьер) — это один из механизмов синхронизации в языке программирования Java, предоставляемый пакетом java.util.concurrent. Он позволяет группе потоков синхронизироваться на определенной точке выполнения, после чего они могут продолжить выполнение параллельно.

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

👉 @java_geek