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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Логические операторы

«И» (AND): конъюнкция, логическое умножение

true && true = true
false && false = false
true && false = false
false && true = false

true & true = true
false & false = false
true & false = false
false & true = false

Побитовые операции:
1010
&&&&
1001
====
1000


Включающее «ИЛИ» (OR): дизъюнкция, логическое сложение

true || true = true
false || false = false
true || false = true
false || true = true

true | true = true
false | false = false
true | false = true
false | true = true

Побитовые операции:
1010
||||
1001
====
1011


Исключающее «ИЛИ» (XOR): строгая дизъюнкция, логическое вычитание

true ^ true = false
false ^ false = false
true ^ false = true
false ^ true = true

Побитовые операции:
1010
^^^^
1001
====
0011


«НЕ» (NOT): инверсия, отрицание

!true = false
!false = true

Побитовый унарный оператор NOT:
~~
01
==
10



Порядок выполнения операторов

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

! ~ (NOT)
& (AND)
^ (XOR)
| (OR)
&& (условный AND)
|| (условный OR)

Если одинаковые операции стоят по соседству, то раньше выполняется та, что левее.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍112
public class Survive {
private Survive internalInstance = new Survive();

public Survive() throws Exception {
throw new Exception("I'm not coming out");
}

public static void main(String[] args) {
try {
Survive b = new Survive();
System.out.println("WIN!");
} catch (Exception ex) {
System.out.println("LOSE!");
}
}
}


#java #quest
⌨️ POJO (Plain Old Java Object) — это простой Java-объект, не зависящий от каких-либо специфичных библиотек, фреймворков или технологий. Такой объект обычно содержит только поля (атрибуты) и методы доступа (геттеры и сеттеры), без дополнительной логики, аннотаций или наследования от специфических классов.

Пример POJO:

public class Person {
private String name;
private int age;

// Конструктор
public Person(String name, int age) {
this.name = name;
this.age = age;
}

// Геттеры и сеттеры
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}


POJO используется для создания простых объектов без привязки к какой-либо специфической архитектуре или фреймворку. Например, в JPA объекты-сущности часто являются POJO, что позволяет их использовать независимо от платформы.

#java #pojo
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍3
⌨️ 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