Java | Фишки и трюки
7.21K subscribers
182 photos
29 videos
6 files
40 links
Java: примеры кода, интересные фишки и полезные трюки

Купить рекламу: https://telega.in/c/java_tips_and_tricks

✍️По всем вопросам: @Pascal4eg
Download Telegram
DataInputStream и DataOutputStream предоставляют методы для чтения и записи примитивных данных из и в поток ввода/вывода. Эти классы добавляют функциональность к обычным потокам ввода/вывода, позволяя удобно считывать и записывать данные различных типов, таких как целые числа, числа с плавающей запятой, символы и т.д., без необходимости вручную преобразовывать их в байты.
👍11👏1
Чистый код: создание, анализ и рефакторинг
Автор: Роберт Мартин

Эту книгу должен прочитать каждый разработчик. А затем перечитывать каждый год! 😁 Плюс для джавистов в том что в книге все примеры написаны на Java.

"Чистый код" Роберта Мартина – это практическое руководство для разработчиков, нацеленное на улучшение качества программного кода. Автор предлагает читателям принципы и практики, которые помогут создавать код, который легко понимать, поддерживать и изменять. Книга рассматривает множество аспектов программирования, включая именование переменных, организацию функций, обработку ошибок, комментирование и многое другое. С использованием конкретных примеров и иллюстраций автор помогает программистам развивать навыки написания "чистого кода" для повышения эффективности и удовлетворения требований современной разработки программного обеспечения.
👍21🔥2
Память кучи

В Java память кучи (heap memory) является областью памяти, где хранятся объекты и массивы. Куча управляется сборщиком мусора (garbage collector), который автоматически освобождает память, занятую объектами, которые больше не используются.

Динамическое выделение
Объекты в Java создаются динамически во время выполнения программы. Куча предоставляет пространство для хранения этих объектов, и их размер может изменяться в процессе выполнения программы.

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

Поколения кучи
Память кучи в Java обычно делится на три поколения: молодое поколение (young generation), поколение средней жизни (tenured/old generation) и поколение постоянных объектов (permanent generation, до Java 7) или область метаспейса (metaspace, начиная с Java 8).

👉 Молодое поколение содержит новые объекты, которые создаются в программе. Сборка мусора часто выполняется в этом поколении.

👉 Поколение средней жизни содержит объекты, которые пережили несколько циклов сборки мусора в молодом поколении.

👉 Поколение постоянных объектов (или область метаспейса) содержит метаданные классов и постоянные строки. В Java 8 и более поздних версиях используется метаспейс вместо постоянного поколения.

Настройка кучи
Размеры и параметры работы сборщика мусора и памяти кучи можно настраивать с использованием опций командной строки при запуске Java-приложения. Например, можно указать максимальный и начальный размеры кучи, выбрать алгоритм сборки мусора и другие параметры.

Производительность и оптимизации
Память кучи и сборка мусора в Java подвергаются постоянным оптимизациям и улучшениям в новых версиях JDK. Производительность приложений может зависеть от эффективности работы сборщика мусора и правильного управления памятью.
🔥12👍62👌1
😁35👍2
Параметр fetch в аннотациях @ManyToOne, @ManyToMany, @OneToOne, @OneToMany определяет как будет загружаться связанная сущность: вместе с загрузкой родительской сущности или в момент обращения к аннотированному полю.

Этот параметр может принимать два значения:

EAGER: при загрузке родительской сущности будет загружена и дочерняя сущность. Это один SQL-запрос с выбором родительской сущности к которой присоединяется (LEFT JOIN) дочерняя.

LAZY: при загрузке родительской сущности, дочерняя сущность загружена не будет. Вместо нее будет создан proxy-объект. С помощью этого proxy-объекта Hibernate будет отслеживать обращение к этой дочерней сущности и при первом обращении загрузит ее в память.

Какой же использовать? Если сущности не большие и связей не много, а проект не сильно нагруженный, то можно использовать EAGER, иначе нагрузка на БД может быть большой и в результате приложение может стать задумчивым.

Но LAZY не панацея, например мы можем выбрать список сущностей и что то с ними делать в цикле обращаясь к полю LAZY, в результате мы получим дополнительный запрос на каждый элемент списка, что так же увеличит нагрузку на БД. В данном случае нужно выбрать это поле как EAGER.

Получается что у нас могут быть разные варианты использования выбранной сущности. Как же быть? Первое что приходит в голову это сделать набор сущностей которые смотрят на одну и ту же таблицу, но в которых параметр fetch задан по разному, в зависимости от использования сущности. Но такой способ выглядит криво: дублирование кода, проблемы с передачей сущности в методы (классы сущностей все разные). В следующих постах поговорим о том как этого избежать. Не переключайте канал.
👍17🔥5👏1
JPA Entity Graph - это механизм, предоставляемый JPA, который позволяет явно указывать, какие атрибуты сущности должны быть загружены или проигнорированы во время выполнения запросов к базе данных. Это может быть полезно для управления жадной загрузкой (eager loading) и ленивой загрузкой (lazy loading) связанных сущностей.

JPA Entity Graph предоставляет более гибкий и декларативный способ управления загрузкой связанных данных по сравнению с использованием параметра fetch в аннотациях связи с другими сущностями. Он также позволяет избежать проблем с N+1 запросами, когда множество связанных сущностей загружается в отдельных запросах.

В нашем примере мы создали именованный граф сущности (person-with-address), который включает атрибуты name из сущности Person и также включает атрибут address с дополнительным подграфом (address-subgraph), который включает атрибут city из сущности Address.

Далее мы используем getEntityGraph для получения ссылки на ранее созданный граф сущности, а затем передаем его в запрос find с использованием соответствующих свойств. Это позволяет загрузить только указанные атрибуты, что может быть полезно для оптимизации производительности и избежания избыточной загрузки данных.

Entity Graph можно так же создавать динамически используя метод createEntityGraph вместо getEntityGraph.
👍13🔥2
Какое объявление i превращает этот цикл в бесконечный? while (i == i + 1) { }
Anonymous Quiz
29%
double i = 1.0 / 0.0;
17%
double i = 0.0 / 1.0;
18%
double i = Double.MAX_VALUE;
6%
double i = Double.MIN_VALUE;
30%
решения не существует
5🔥1🎉1
Чем отличаются эти два способа определения массива?

int[] array = new int[]{1,2,3}
int[] array = {1,2,3}

Ответ: ничем не отличается, эти два определения идентичны на уровне байт-кода.
👍36😁4🔥3
Проблема N+1 (N+1 Issue) в JPA (Java Persistence API) возникает, когда при получении списка сущностей с их связанными сущностями (например, при использовании отношения OneToMany или ManyToOne), для каждой основной сущности выполняется дополнительный запрос для загрузки связанной сущности. Это приводит к выполнению N+1 запросов к базе данных, где N - количество основных сущностей.

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

Использование управления загрузкой, такого как JOIN FETCH или использование JPA Entity Graphs, позволяет предотвратить проблему N+1 и повысить производительность при работе с базой данных через JPA.
👍17🔥1
PrintStream является классом, предназначенным для удобного вывода различных типов данных в поток вывода. Он является подклассом OutputStream и предоставляет методы для вывода данных различных примитивных типов, строк и объектов в удобном для чтения текстовом формате.

В этом примере PrintStream используется для вывода данных как в консоль, так и в файл. Он обеспечивает удобный способ форматирования и вывода данных различных типов. Класс PrintStream также автоматически преобразует различные типы данных в их текстовое представление перед выводом.
👍9👏1
😁23🤣2🔥1💯1
SOLIDпринципы объектно‑ориентированного программирования

SOLID — это аббревиатура пяти основных принципов проектирования в объектно‑ориентированном программировании — Single responsibility, Open-closed, Liskov substitution, Interface segregation и Dependency inversion.

В переводе на русский: принципы единственной ответственности, открытости / закрытости, подстановки Барбары Лисков, разделения интерфейса и инверсии зависимостей.

Аббревиатура SOLID была предложена Робертом Мартином, автором нескольких книг, широко известным в сообществе разработчиков. Следование принципам позволяет строить на базе ООП масштабируемые и сопровождаемые программные продукты с понятной бизнес‑логикой. Код, который написан с соблюдением принципов SOLID, проще понимать, поддерживать, расширять или изменять его функциональность.

Принцип единственной обязанности / ответственности (single responsibility principle / SRP) обозначает, что каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены исключительно на обеспечение этой обязанности.

Принцип открытости / закрытости (open-closed principle / OCP) декларирует, что программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения. Это означает, что эти сущности могут менять свое поведение без изменения их исходного кода.

Принцип подстановки Барбары Лисков (Liskov substitution principle / LSP) в формулировке Роберта Мартина: «функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом».

Принцип разделения интерфейса (interface segregation principle / ISP) в формулировке Роберта Мартина: «клиенты не должны зависеть от методов, которые они не используют». Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют.

Принцип инверсии зависимостей (dependency inversion principle / DIP) — модули верхних уровней не должны зависеть от модулей нижних уровней, а оба типа модулей должны зависеть от абстракций; сами абстракции не должны зависеть от деталей, а вот детали должны зависеть от абстракций.
👍17❤‍🔥1🔥1
public class Quest {
public static void main(String[] args) {
try {
System.out.println("Hello World");
} catch (IOException e) {
System.out.println("Error");
}
}
}
Какой будет результат выполнения кода?
Anonymous Quiz
78%
Hello World
7%
Error
15%
ошибка компиляции
👍3🎉1
⌨️ Управление доступом к членам класса

Модификаторы уровня доступа определяют, могут ли другие классы использовать определенное поле или вызывать определенный метод.

Существует 4 уровня доступа:

private
Указывает, что доступ возможен только в его собственном классе.

package-private (нет явного модификатора)
Указывает, что доступ только внутри своего собственного пакета.

protected
Указывает, что доступ возможен только внутри его собственного пакета (как в случае с package-private) и, кроме того, для подкласса его класса в другом пакете.

public
Указывает, что доступ возможен отовсюду.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥1😁1
JIT-компилятор

На начальном этапе выполнения программы байт-код интерпретируется JVM. Это позволяет быстро запускать программы без необходимости предварительной компиляции в машинный код.

JIT-компилятор является ключевым элементом виртуальной машины Java (JVM). Он компилирует байт-код часто вызываемых методов в машинный код во время выполнения. Следовательно, он отвечает за оптимизацию программ Java.

JVM автоматически отслеживает, какие методы выполняются. Как только метод становится пригодным для JIT-компиляции, его планируется компилировать в машинный код. Этот метод так же известен как горячий метод. Эта компиляция в машинный код происходит в отдельном потоке JVM. В результате он не прерывает выполнение текущей программы. После компиляции в машинный код, метод работает быстрее.

Таким образом, JIT-компиляция в Java позволяет достичь компромисса между портативностью байт-кода и производительностью машинного кода. Этот механизм позволяет Java-приложениям быть эффективными на различных платформах, так как байт-код может быть выполнен на любой машине, в то время как JIT-компиляция обеспечивает высокую производительность приложений в процессе их выполнения.
👍1111🔥1
⌨️ Class Loaders

В Java, Class Loader (загрузчик классов) является частью Java Runtime Environment (JRE), которая ответственна за загрузку классов в виртуальную машину Java (JVM) во время выполнения программы. Class Loader осуществляет поиск и загрузку классов в память JVM по их именам.

Class Loader имеет иерархическую структуру и состоит из трех основных типов:

1️⃣ Bootstrap Class Loader (Загрузчик базовых классов): Этот загрузчик является частью ядра JVM и отвечает за загрузку системных классов Java, таких как java.lang.Object, java.lang.String и другие. Он является самым высоким в иерархии загрузчиком.

2️⃣ Extension Class Loader (Загрузчик расширений): Этот загрузчик наследуется от Bootstrap Class Loader и загружает классы из расширенной библиотеки Java (расположенной в директории jre/lib/ext).

3️⃣ Application Class Loader (Загрузчик приложений): Также известный как System Class Loader, этот загрузчик загружает классы из путей, указанных в переменной окружения CLASSPATH. Он также загружает классы из текущего рабочего каталога приложения.

Когда Java-программа запускается, система Class Loader следует иерархии загрузки классов. Если класс не найден в одном загрузчике, система пытается найти его в следующем в иерархии.

Процесс загрузки класса включает в себя три этапа:

1️⃣ Загрузка (Loading): Загрузчик находит байт-код класса и загружает его в память.

2️⃣ Связывание (Linking): На этом этапе проводится проверка байт-кода, выделение памяти для статических полей, и разрешение ссылок на другие классы.

3️⃣ Инициализация (Initialization): Выполняются статические блоки кода и инициализируются статические переменные.

Класс ClassLoader предоставляет методы для динамической загрузки классов во время выполнения. Работа с Class Loader'ами может быть полезной, например, при реализации механизмов плагинов и динамической загрузки классов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72🔥2👎1
Метод dropWhile был введен в интерфейсе Stream в JDK 9. Этот метод позволяет пропускать элементы в начале потока данных, пока они удовлетворяют определенному условию, и возвращает новый поток, начиная с первого элемента, который не соответствует условию.

В нашем примере метод dropWhile используется для пропуска элементов в потоке до тех пор, пока они меньше 0. После первого элемента, не соответствующего условию, оставшиеся элементы добавляются в новый поток.
👍14🔥1
Класс Properties

В Java класс Properties представляет собой таблицу хэш-значений ключ-значение. Он является частью пакета java.util, и обычно используется для работы с конфигурационными файлами, настройками приложений и другими данными в формате ключ-значение.

Некоторые методы класса Properties:

setProperty(String key, String value) - добавление или изменение значения ключа.

getProperty(String key) - получение значения по ключу.

load(InputStream in) - загрузка свойств из InputStream.

store(OutputStream out, String comments) - сохранение свойств в OutputStream.

defaults(Properties defaults) - устанавливает значения по умолчанию, которые будут использоваться при поиске значения для ключа, если оно не найдено в текущих свойствах.

Пример файла Properties:
version=1.0
name=TestApp
👍9👏2
😁15🤣7