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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ ORM и JPA

ORM (Object-Relational Mapping) — это технология, которая позволяет автоматически преобразовывать данные между объектами в программном коде и записями в реляционной базе данных. Благодаря ORM, программисты могут работать с базой данных на уровне объектов, а не SQL-запросов, что упрощает разработку.

JPA (Java Persistence API) — это стандарт спецификации ORM в Java. JPA определяет набор интерфейсов и аннотаций для работы с объектами и их сохранением в базу данных. Однако JPA сама по себе не является реализацией, а только задает стандарт. Реализации JPA включают Hibernate, EclipseLink и другие.

#java #jpa
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151
⌨️ HQL (Hibernate Query Language) — это язык запросов, используемый в Hibernate для работы с объектами, а не с таблицами базы данных. HQL основан на синтаксисе SQL, но оперирует сущностями и их атрибутами, вместо строк и столбцов базы данных.

Особенности HQL:

✔️ Запросы формулируются относительно классов и их полей, а не таблиц.

✔️ Поддерживает агрегатные функции (например, COUNT, SUM).

✔️ Поддерживает JOIN для работы с ассоциациями между объектами.

✔️ HQL автоматически преобразуется в SQL, что облегчает работу с реляционной базой данных, абстрагируя детали.

Пример HQL-запроса:

SELECT u FROM User u WHERE u.name = :name


Здесь User — это класс сущности, а запрос вернет объекты этого класса.

#java #HQL #Hibernate
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
public class Quest {
public static void main(String[] args) {
int[][] tests = {
{6, 5, 4, 3, 2, 1},
{1, 2},
{1, 2, 3},
{1, 2, 3, 4},
{1}
};
int n = 0;
try {
int i = 0;
while (true) {
if (thirdElementIsThree(tests[i++])) n++;
}
} catch (ArrayIndexOutOfBoundsException e) {
}
System.out.println(n);
}

private static boolean thirdElementIsThree(int[] a) {
return (a.length >= 3) & (a[2] == 3);
}
}


#java #quest
5
🌱 Spring Boot - это инструмент, который значительно упрощает разработку приложений на основе Spring, предоставляя возможность создавать автономные, готовые к использованию приложения с минимальной конфигурацией.

Автоконфигурация
Spring Boot автоматически настраивает компоненты приложения на основе зависимостей, которые вы добавляете в проект. Это избавляет от необходимости писать обширные XML-конфигурации или классы конфигурации.

Встроенные серверы
Spring Boot предоставляет возможность запускать приложение с встроенными серверами, такими как Tomcat или Jetty. Это означает, что вам не нужно отдельно настраивать сервер — приложение можно запустить как обычный JAR-файл.

Spring Initializr
Веб-инструмент, который позволяет быстро генерировать новый проект Spring Boot с нужными зависимостями, что делает старт разработки ещё проще.

Actuator
Модуль для мониторинга и управления приложением на продакшене. Он предоставляет различные эндпоинты для проверки состояния, статистики и метрик приложения.

Миграции баз данных
Spring Boot поддерживает интеграцию с инструментами миграции баз данных, такими как Flyway и Liquibase, что упрощает управление схемами базы данных.

#java #SpringBoot
Please open Telegram to view this post
VIEW IN TELEGRAM
👍121🔥1
🌱 Service Discovery это механизм, который позволяет распределенным приложениям (микросервисам) динамически находить друг друга для взаимодействия, независимо от того, где они развернуты (например, в облаке или локально). Это особенно важно для микросервисной архитектуры, где сервисы могут масштабироваться горизонтально, изменять свои IP-адреса и запускаться на различных узлах сети.

Spring Framework предлагает решения для реализации Service Discovery, такие как Spring Cloud, который интегрируется с популярными механизмами регистрации сервисов, такими как: Netflix Eureka, HashiCorp Consul, Apache Zookeeper.

Как работает процесс Service Discovery:

✔️ Регистрация сервиса — каждый микросервис при запуске автоматически регистрируется в реестре (например, Eureka или Consul), передавая своё местоположение (IP и порт).

✔️ Обнаружение сервиса — при необходимости взаимодействовать с другим микросервисом, сервис может запрашивать реестр для получения списка доступных сервисов и их адресов.

✔️ Health Checks — в большинстве систем Service Discovery интегрированы проверки состояния сервисов. Если сервис становится недоступен, он удаляется из реестра.


Зачем это нужно?

✔️ Масштабируемость: При динамическом добавлении и удалении экземпляров сервисов, они автоматически обнаруживаются и учитываются другими сервисами.

✔️ Гибкость развертывания: Сервисы могут развертываться на разных машинах и сетях, не требуя жесткой привязки к IP-адресам.

✔️ Устойчивость: В случае отказа одного из экземпляров сервиса другие сервисы могут быть обнаружены и использованы.

#java #ServiceDiscovery
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51
⌨️ Внутренняя реализация ArrayList

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

ArrayList основан на массиве объектов. Это означает, что под капотом у него есть массив фиксированного размера. Когда этот массив заполняется, создается новый массив большего размера, в который копируются элементы старого массива, а затем старый массив удаляется.

Размер и емкость

✔️ Размер (size) — это количество элементов, которые фактически содержатся в ArrayList.

✔️ Емкость (capacity) — это текущий размер внутреннего массива. Когда количество элементов превышает емкость, массив расширяется.

Когда ArrayList инициализируется, его емкость по умолчанию равна 10. Если количество элементов в массиве превышает емкость, массив автоматически увеличивается. Обычно емкость увеличивается по формуле: новая емкость = старая емкость * 1.5.

Для удаления элементов используется метод remove(int index). После удаления элемента все элементы, находящиеся справа от удаленного, смещаются на одну позицию влево, что требует временных затрат O(n).

После удаления элементов ArrayList не автоматически уменьшает емкость внутреннего массива, то есть массив может занимать больше памяти, чем требуется для хранения фактических элементов. Однако для оптимизации можно вручную уменьшить емкость до текущего размера с помощью метода trimToSize().

Одним из преимуществ ArrayList является возможность доступа к элементам по индексу за время O(1). Это возможно благодаря тому, что элементы хранятся в массиве, и доступ к ним осуществляется через индекс.

#java #ArrayList
Please open Telegram to view this post
VIEW IN TELEGRAM
👍142🤓2
🔄 Бесконечные потоки

Интерфейс Stream имеет два статических метода для генерации бесконечных потоков: iterate() и generate().

iterate(final T seed, final UnaryOperator<T> f) возвращает бесконечный последовательный упорядоченный поток, созданный путем итеративного применения функции f к исходному элементу начального значения, создавая поток, состоящий из начального числа, f(начальное число), f(f(начальное число)) и т. д.

generate(Supplier<? extends T> s) возвращает бесконечный последовательный неупорядоченный поток, в котором каждый элемент создается предоставленным поставщиком (Supplier). Это подходит для генерации константных потоков, потоков случайных элементов и т. д.

📌 При работе с бесконечными потоками, крайне важно вызвать метод limit() перед вызовом терминальной операции, иначе наша программа будет работать бесконечно.
🔥133
⌨️ В чём разница между TreeSet и HashSet?

TreeSet и HashSet — это два класса, реализующих интерфейс Set, но они имеют разные внутренние механизмы и свойства.

Структура данных

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

✔️ TreeSet использует красно-черное дерево (Red-Black Tree), что позволяет хранить элементы в отсортированном порядке (естественном порядке элементов или порядке, определённом компаратором).


Порядок элементов

✔️ HashSet не гарантирует какого-либо порядка элементов. Порядок может быть случайным, и он не сохраняется при добавлении/удалении элементов.

✔️ TreeSet хранит элементы в отсортированном порядке. Если элементы реализуют интерфейс Comparable, то сортировка будет основана на их естественном порядке (например, для чисел — по возрастанию). Также можно задать пользовательский порядок с помощью объекта Comparator.


Скорость операций

✔️ HashSet обеспечивает O(1) для операций добавления, удаления и поиска (в среднем, если хеш-функция работает эффективно и коллизий мало).

✔️ TreeSet обеспечивает O(log n) для операций добавления, удаления и поиска из-за использования сбалансированного дерева.


Поддержка дополнительных операций

✔️ HashSet не поддерживает дополнительные методы для работы с диапазонами или порядком элементов.

✔️ TreeSet предоставляет такие методы, как subSet(), headSet(), tailSet(), которые позволяют работать с диапазонами элементов в отсортированном множестве.


Null-значения

✔️ HashSet может хранить одно null значение.

✔️ TreeSet не позволяет хранить null значения, так как при добавлении null неясно, как его сравнивать с другими элементами.


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

✔️ Используйте HashSet, если вам не важен порядок элементов и вам нужна максимальная производительность.

✔️ Используйте TreeSet, если нужно поддерживать элементы в отсортированном порядке.

#java #HashSet #TreeSet
Please open Telegram to view this post
VIEW IN TELEGRAM
👍164🔥3
public class Quest {
public static void main(String[] args) {
int a = 5;
int b = 10;
int result = multiply(a, b);
System.out.println(result);
}

public static int multiply(int x, int y) {
if (y == 0) {
return 0;
} else {
return x + multiply(x, y - 1);
}
}
}

#java #quest
4
Что выведет код?
Anonymous Quiz
54%
50
11%
5
3%
10
33%
Бесконечная рекурсия
🎉6🌚4🫡1
public class Test {

public static int VAL;

{
VAL = 5;
}

public Test() {
VAL = 10;
}

public static void print() {
System.out.println(VAL);
}

}

public class Quest {
public static void main(String[] args) {
Test.print();
}
}


#java #quest
5
Что выведет код?
Anonymous Quiz
12%
0
35%
5
24%
10
29%
<ошибка компиляции>
🎉8
🌱 Spring Cloud Config — это проект в экосистеме Spring, который предоставляет сервер и клиент для централизованного управления конфигурацией в распределённых системах. Основная идея Spring Cloud Config — это вынесение конфигурационных файлов из приложений в единое место (например, репозиторий Git), чтобы облегчить управление конфигурацией для различных сервисов в микросервисной архитектуре.

Основные компоненты

✔️ Config Server — сервер, который хранит конфигурации (обычно в Git) и раздает их микросервисам.

✔️ Config Client — клиент в микросервисах, который получает конфигурации от Config Server.


Возможности

✔️ Централизация конфигураций всех сервисов.

✔️ Поддержка версионирования конфигураций (например, через Git).

✔️ Динамическое обновление конфигураций без перезапуска приложений с помощью Spring Cloud Bus.

✔️ Поддержка различных сред и профилей (dev, prod и т.д.).


Пример настройки Config Server:

spring:
cloud:
config:
server:
git:
uri: https://github.com/your-repo/config-repo


Пример настройки Config Client:

spring:
cloud:
config:
uri: http://localhost:8888
profile: dev


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

Недостатки: важен контроль за доступом и стабильностью Config Server.

#java #Spring #Cloud #Config
Please open Telegram to view this post
VIEW IN TELEGRAM
👍153🔥1
⌨️ События жизненного цикла объекта JPA

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

JPA определяет семь событий жизненного цикла:

@PrePersist - перед тем, как вызывается persist для нового объекта

@PostPersist - после того, как вызывается persist для нового объекта

@PreRemove - прежде чем сущность будет удалена

@PostRemove - после удаления объекта

@PreUpdate - перед операцией обновления

@PostUpdate - после обновления сущности

@PostLoad - после загрузки объекта

Итак, если мы создаем новую сущность и вызываем метод сохранения нашего репозитория, вызывается наш метод, аннотированный @PrePersist, затем запись вставляется в базу данных и, наконец, вызывается наш метод @PostPersist. Если мы используем @GeneratedValue для автоматической генерации наших первичных ключей, мы можем ожидать, что этот ключ будет доступен в методе @PostPersist.

Для операций @PostPersist, @PostRemove и @PostUpdate в документации упоминается, что эти события могут произойти сразу после выполнения операции или в конце транзакции.

Следует отметить, что обратный вызов @PreUpdate вызывается только в том случае, если данные действительно изменяются, то есть если необходимо выполнить фактический оператор обновления SQL. Обратный вызов @PostUpdate вызывается независимо от того, действительно ли что-то изменилось.

Если какой-либо из наших обратных вызовов для сохранения или удаления объекта выдаст исключение, транзакция будет отменена.


@Entity
public class User {
private static Log log = LogFactory.getLog(User.class);

@Id
@GeneratedValue
private int id;

private String userName;
private String firstName;
private String lastName;
@Transient
private String fullName;

// getter and setter

@PrePersist
public void logNewUserAttempt() {
log.info("Attempting to add new user with username: " + userName);
}

@PostPersist
public void logNewUserAdded() {
log.info("Added user '" + userName + "' with ID: " + id);
}

@PreRemove
public void logUserRemovalAttempt() {
log.info("Attempting to delete user: " + userName);
}

@PostRemove
public void logUserRemoval() {
log.info("Deleted user: " + userName);
}

@PreUpdate
public void logUserUpdateAttempt() {
log.info("Attempting to update user: " + userName);
}

@PostUpdate
public void logUserUpdate() {
log.info("Updated user: " + userName);
}

@PostLoad
public void logUserLoad() {
fullName = firstName + " " + lastName;
}
}


#java #Entity #Lifecycle
Please open Telegram to view this post
VIEW IN TELEGRAM
👍134🔥1
⌨️ Jasypt (Java Simplified Encryption) — это библиотека для шифрования и защиты конфиденциальных данных в Java-приложениях. Она упрощает процесс шифрования и дешифрования данных, обеспечивая простой и интуитивно понятный API. Jasypt особенно полезен для шифрования конфигурационных файлов (например, паролей для баз данных), чувствительной информации в базах данных и других данных, требующих защиты.

Подключение зависимости:

<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
</dependency>


Пример использования:

String myEncryptionPassword = "mySuperSecretPassword";
String secretData = "secret data";

AES256TextEncryptor textEncryptor = new AES256TextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);
String myEncryptedText = textEncryptor.encrypt(secretData);
System.out.println(myEncryptedText);
// DpMHE0Yy+6Ctlyx5lchU8j50Y2TRlGSOjHwIqAroxvmgq0VMijs/y8GkR9vcF1Pg

String plainText = textEncryptor.decrypt(myEncryptedText);
System.out.println(plainText); // secret data



Применение в Spring Boot

Для интеграции с Spring Boot Jasypt позволяет зашифровать чувствительные параметры конфигурации. Например, конфигурация для базы данных может быть записана так:

spring:
datasource:
url: ENC(encrypted-url)
username: ENC(encrypted-username)
password: ENC(encrypted-password)


Затем Jasypt автоматически расшифровывает эти значения при запуске приложения.

#java #Jasypt #cryptography
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍133
⌨️ Как добавить элемент в середину массива?

Есть несколько способов добавить элемент в середину массива. Однако, поскольку массивы имеют фиксированную длину, напрямую добавить элемент в существующий массив нельзя — нужно создавать новый массив с увеличенной длиной и копировать данные. Рассмотрим несколько способов:

1️⃣ Копирование вручную

Суть в том что бы создать новый массив на 1 элемент больше оригинального и перенести элементы из старого, не забыв при этом вставить новый элемент.


int[] array = {1, 2, 4, 5};
int index = 2; // индекс, куда вставить новый элемент
int newElement = 3;

// Создаем новый массив на 1 больше
int[] newArray = new int[array.length + 1];

// Копируем элементы до позиции вставки
for (int i = 0; i < index; i++) {
newArray[i] = array[i];
}

// Вставляем новый элемент
newArray[index] = newElement;

// Копируем оставшиеся элементы
for (int i = index + 1; i < newArray.length; i++) {
newArray[i] = array[i - 1];
}

// Печатаем новый массив
System.out.println(Arrays.toString(newArray)); // [1, 2, 3, 4, 5]


2️⃣ Использование коллекций (например, ArrayList)

ArrayList динамический по размеру, и можно легко вставить элемент в любое место с помощью метода add(index, element).


Integer[] array = {1, 2, 4, 5};
int index = 2; // индекс, куда вставить новый элемент
int newElement = 3;

List<Integer> list = new ArrayList<>(Arrays.asList(array));

// Вставляем элемент
list.add(index, newElement);

// Создаем новый массив на 1 больше
Integer[] newArray = list.toArray(array);

// Печатаем новый массив
System.out.println(Arrays.toString(newArray)); // [1, 2, 3, 4, 5]


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

Метод System.arraycopy позволяет эффективно копировать части массива.


int[] array = {1, 2, 4, 5};
int index = 2; // индекс, куда вставить новый элемент
int newElement = 3;

// Создаем новый массив на 1 больше
int[] newArray = new int[array.length + 1];

// Копируем элементы до позиции вставки
System.arraycopy(array, 0, newArray, 0, index);

// Вставляем новый элемент
newArray[index] = newElement;

// Копируем оставшиеся элементы
System.arraycopy(array, index, newArray, index + 1, array.length - index);

// Печатаем новый массив
System.out.println(Arrays.toString(newArray)); // [1, 2, 3, 4, 5]


#java #array
Please open Telegram to view this post
VIEW IN TELEGRAM
👍113👎2
public class Quest {
public static void main(String[] args) {
final String pig = "length: 10";
final String dog = "length: " + pig.length();

System.out.println("Animals are equal: " + pig == dog);
}
}

#java #quest
👍2
⌨️ Выполнение команды в командной строке с выводом результата


public class CommandLine {
public static void main(String[] args) throws IOException {
Runtime rt = Runtime.getRuntime();
String[] commands = {"ping", "-c 5", "google.com"};
Process proc = rt.exec(commands);

BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));

BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));

// Read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}

// Read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
}


Метод Runtime.getRuntime() возвращает объект, представляющий текущую среду выполнения Java. Этот объект позволяет запускать команды системы.

Метод exec() запускает системную команду и возвращает объект Process, который представляет запущенный процесс. Команда, которую нужно выполнить, передается как массив строк.

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

Вывод:

Here is the standard output of the command:

PING google.com (173.194.222.138): 56 data bytes
64 bytes from 173.194.222.138: icmp_seq=0 ttl=60 time=39.479 ms
64 bytes from 173.194.222.138: icmp_seq=1 ttl=60 time=39.753 ms
64 bytes from 173.194.222.138: icmp_seq=2 ttl=60 time=47.982 ms
64 bytes from 173.194.222.138: icmp_seq=3 ttl=60 time=39.569 ms
64 bytes from 173.194.222.138: icmp_seq=4 ttl=60 time=39.850 ms

--- google.com ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 39.479/41.327/47.982/3.330 ms
Here is the standard error of the command (if any):


#java #Runtime #exec
Please open Telegram to view this post
VIEW IN TELEGRAM
👍93