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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
Что выведет код?
Anonymous Quiz
42%
50
24%
51
35%
ошибка компиляции
🎉1
🖥 UPSERT (Update or Insert) в PostgreSQL

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

Есть две опции что должно происходить при конфликте при вставке: DO UPDATE и DO NOTHING. Тут все понятно из названия, или обновить запись или ни делать ничего.


INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...)
ON CONFLICT (conflict_target)
DO UPDATE SET column1 = value1, column2 = value2, ...;


conflict_target это колонка или набор колонок, которые используются для определения конфликта, обычно это первичный ключ или уникальный индекс. conflict_target можно не указывать и тогда при любом конфликте (дублируется первичный ключ, нарушение уникального индекса и тд.) сработает UPDATE или ничего.

Пример:

CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE,
email TEXT
);

INSERT INTO users (id, username, email)
VALUES (1, 'user1', 'user1@example.com')
ON CONFLICT
DO NOTHING;

INSERT INTO users (id, username, email)
VALUES (1, 'user1', 'user1@example.com')
ON CONFLICT
DO NOTHING;


Первый INSERT добавит запись, а второй ничего не сделает, так как произойдет дублирование первичного ключа.

#java #PostgreSQL #upsert #update #insert
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥21
public class Quest {
public static void main(String[] args) {
Short b = 50;
inc(b);
System.out.println(b);
}
private static void inc(Short num) {
num++;
}
}
Что выведет код?
Anonymous Quiz
40%
50
37%
51
23%
ошибка компиляции
👍6🎉3
⌨️ Класс Objects

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

Класс финальный и создать его не получится, об этом позаботились разработчики:

public final class Objects {
private Objects() {
throw new AssertionError("No java.util.Objects instances for you!");
}
...
}


Метод equals для NPE-безопасного сравнения объектов:

public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}

Метод toString для NPE-безопасного преобразования объекта в строку:

public static String toString(Object o) {
return String.valueOf(o);
}


Метод toString с дефолтным значением для случая если объект равен null:

public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}


Метод requireNonNull позволяет чекнуть объект на null:

public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}


Забавные методы isNull и nonNull проверяют переменную на null и на не null:

public static boolean isNull(Object obj) {
return obj == null;
}

public static boolean nonNull(Object obj) {
return obj != null;
}


#java #Objects #NPE
Please open Telegram to view this post
VIEW IN TELEGRAM
👍144🥱2
⌨️ Приведение типов. Понижение и повышение типа

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

В Java существуют несколько разновидностей приведения:

✔️ Тождественное (identity). Преобразование выражения любого типа к точно такому же типу всегда допустимо и происходит автоматически.

✔️ Расширение (повышение, upcasting) примитивного типа (widening primitive). Означает, что осуществляется переход от менее емкого типа к более ёмкому. Например, от типа byte (длина 1 байт) к типу int (длина 4 байта). Такие преобразование безопасны в том смысле, что новый тип всегда гарантировано вмещает в себя все данные, которые хранились в старом типе и таким образом не происходит потери данных. Этот тип приведения всегда допустим и происходит автоматически.

✔️ Сужение (понижение, downcasting) примитивного типа (narrowing primitive). Означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные. Например, если число типа int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны. В Java такое преобразование должно совершаться явным образом, при этом все старшие биты, не умещающиеся в новом типе, просто отбрасываются - никакого округления или других действий для получения более корректного результата не производится.

✔️ Расширение объектного типа (widening reference). Означает неявное восходящее приведение типов или переход от более конкретного типа к менее конкретному, т.е. переход от потомка к предку. Разрешено всегда и происходит автоматически.

✔️ Сужение объектного типа (narrowing reference). Означает нисходящее приведение, то есть приведение от предка к потомку (подтипу). Возможно только если исходная переменная является подтипом приводимого типа. При несоответствии типов в момент выполнения выбрасывается исключение ClassCastException. Требует явного указания типа.

✔️ Преобразование к строке (to String). Любой тип может быть приведен к строке, т.е. к экземпляру класса String.

✔️ Запрещенные преобразования (forbidden). Не все приведения между произвольными типами допустимы. Например, к запрещенным преобразованиям относятся приведения от любого ссылочного типа к примитивному и наоборот (кроме преобразования к строке). Кроме того, невозможно привести друг к другу классы, находящиеся на разных ветвях дерева наследования и т.п.

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

Для проверки возможности приведения нужно воспользоваться оператором instanceof:

Parent parent = new Child();
if (parent instanceof Child) {
Child child = (Child) parent;
}


#java #casting #upcasting #downcasting
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥101
public class Quest {
public static void main(String[] args) {
System.out.println(concat1() < concat2());
}
private static long concat1() {
long start = System.nanoTime();
String s = "";
for (int i = 0; i < 1000; i++) {
s += "-" + i;
}
return System.nanoTime() - start;
}

private static long concat2() {
long start = System.nanoTime();
StringBuilder s = new StringBuilder();
for (int i = 0; i < 1000; i++) {
s.append("-" + i);
}
return System.nanoTime() - start;
}
}

#java #quest
👏3
Что выведет код?
Anonymous Quiz
40%
true
60%
false
5
⌨️ Автоупаковка (autoboxing). Правила упаковки примитивных типов в классы-обертки

Автоупаковка - это механизм неявной инициализации объектов классов-оберток (Byte, Short, Integer, Long, Float, Double, Character, Boolean) значениями соответствующих им исходных примитивных типов (byte, short, int...), без явного использования конструктора класса.

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

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

Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива типу класса-обертки. Например, попытка упаковать переменную типа byte в Short, без предварительного явного приведения byte в short вызовет ошибку компиляции.

Автоупаковка констант примитивных типов допускает более широкие границы соответствия. В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов:

✔️ неявное расширение/сужение исходного типа примитива до типа примитива, соответствующего классу-обертке (для преобразования int в Byte, сначала компилятор самостоятельно неявно сужает int к byte)

✔️ автоупаковку примитива в соответствующий класс-обертку. Однако, в этом случае существуют два дополнительных ограничения:

a) присвоение примитива обертке может производится только оператором = (нельзя передать такой примитив в параметры метода без явного приведения типов)

b) тип левого операнда не должен быть старше чем Character, тип правого не должен старше, чем int: допустимо расширение/сужение byte в/из short, byte в/из char, short в/из char и только сужение byte из int, short из int, char из int. Все остальные варианты требуют явного приведения типов).

Дополнительной особенностью целочисленных классов-оберток, созданных автоупаковкой констант в диапазоне -128 ... +127 является то, что они кэшируются JVM. Поэтому такие обертки с одинаковыми значениями будут являться ссылками на один объект.

#java #autoboxing
Please open Telegram to view this post
VIEW IN TELEGRAM
8
public class Quest {
public static void main(String[] args) {
System.out.println(calc(10, 5));
}

private static int calc(int i, int j) {
int result = i + j;
return result;

result = i - j;
return result;
}
}
3
Что выведет код?
Anonymous Quiz
32%
15
9%
5
59%
ошибка компиляции
👍7🎉3
🌱 Spring Boot Actuator — это подмножество библиотек Spring Boot, которое предоставляет функции мониторинга и управления работающим приложением. Он добавляет несколько полезных средств для разработки, диагностики и управления приложениями, включая метрики, проверку состояния, аудит и прочее.

Метрики (Metrics)
Actuator собирает информацию о работе приложения, такую как использование памяти, процессора, количество запросов и их время обработки. Метрики могут быть доступны через конечные точки или интегрированы с системами мониторинга, такими как Prometheus, Graphite и другие.

Конечные точки (Endpoints)
Actuator предоставляет несколько конечных точек, которые можно использовать для получения информации о состоянии приложения. Некоторые из них:
/actuator/health - возвращает информацию о состоянии приложения.
/actuator/info - предоставляет общую информацию о приложении.
/actuator/metrics - возвращает метрики приложения.
/actuator/env - показывает текущее состояние окружения, включая системные свойства и переменные окружения.

Проверка состояния (Health Checks)
Actuator может проверять состояние различных компонентов приложения (например, баз данных, внешних сервисов и т.д.) и предоставлять общую оценку состояния.

Аудит (Auditing)
Ведение журнала событий приложения, таких как аутентификация пользователей или изменение конфигураций.

HTTP-трейс (HTTP Tracing)
Возможность отслеживания всех входящих HTTP-запросов и ответов.

Для подключения нужно добавить зависимость:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

и добавить в файл конфигурации:

management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always


#java #actuator #health
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🥱31
⌨️ Литералы — это явно заданные значения в коде программы — константы определенного типа, которые находятся в коде в момент запуска.


class Test {
int a = 0b1101010110;
public static void main(String[] args) {
System.out.println("Hello world!");
}
}


В этом классе “Hello world!” — литерал.

Переменная a - тоже литерал.

Литералы бывают разных типов, которые определяются их назначением и способом написания.

#java #literals
Please open Telegram to view this post
VIEW IN TELEGRAM
👍131
⌨️ Семафор (Semaphore) - класс из пакета java.util.concurrent, предназначенный для управления доступом к общим ресурсам в многопоточных приложениях. Он позволяет ограничить количество потоков, которые могут одновременно использовать определенный ресурс.

Семафор управляет набором разрешений, и поток может запросить или освободить разрешение, тем самым контролируя доступ к общим ресурсам.

Конструктор:
Semaphore(int permits) - создает семафор с указанным числом разрешений.

Методы для получения разрешений:

void acquire() - запрашивает одно разрешение. Если разрешение недоступно, поток блокируется до тех пор, пока разрешение не станет доступным.

void acquire(int permits) - запрашивает указанное количество разрешений.

boolean tryAcquire() - запрашивает одно разрешение, если оно доступно, не блокируя поток. Возвращает true, если разрешение получено, и false в противном случае.

boolean tryAcquire(long timeout, TimeUnit unit) - запрашивает одно разрешение, если оно доступно в течение указанного времени. Возвращает true, если разрешение получено, и false в противном случае.

Методы для освобождения разрешений:

void release() - освобождает одно разрешение, увеличивая внутренний счетчик разрешений.

void release(int permits) - освобождает указанное количество разрешений.

Пример:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
private static final int MAX_CONCURRENT_THREADS = 3;
private static final Semaphore semaphore = new Semaphore(MAX_CONCURRENT_THREADS);

public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new Worker(i)).start();
}
}

static class Worker implements Runnable {
private final int id;

Worker(int id) {
this.id = id;
}

@Override
public void run() {
try {
System.out.println("Thread " + id + " is waiting for a permit.");
semaphore.acquire();
System.out.println("Thread " + id + " acquired a permit.");

// Simulate some work with a sleep
Thread.sleep(2000);

System.out.println("Thread " + id + " releasing a permit.");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


В этом примере создается семафор, который позволяет одновременно работать трем потокам. Остальные потоки будут ждать, пока не освободится разрешение. Каждый поток выполняет работу (симулированную с помощью Thread.sleep(2000)), после чего освобождает разрешение, позволяя другому ожидающему потоку приступить к работе.

#java #semaphore
Please open Telegram to view this post
VIEW IN TELEGRAM
👍162
public class Quest {
public final int value = 4;
public void doIt() {
int value = 6;
Runnable r = new Runnable() {
public final int value = 8;
public void run() {
int value = 10;
System.out.println(this.value);
}
};
r.run();
}
public static void main(String[] args) {
new Quest().doIt();
}
}

#java #quest
Что выведет код?
Anonymous Quiz
27%
4
8%
6
37%
8
28%
10
🎉8
⌨️ Какая основная разница между String, StringBuffer, StringBuilder?

Класс String является неизменяемым (immutable) - модифицировать объект такого класса нельзя, можно лишь заменить его созданием нового экземпляра.

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

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

#java #String #StringBuffer #StringBuilder
Please open Telegram to view this post
VIEW IN TELEGRAM
👍113
🍓31👍42❤‍🔥2
🖥 Интересно про то как у нас в Java 23 должна была быть, но не будет, интерполяция строк (String Templates)

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

Это должно было выглядеть так:
String name = "Melissa";
System.out.println("Hello, \{name}!");
// Hello, Melissa!

Habr

#java #StringTemplates
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍1
⌨️ PriorityQueue — это реализация структуры данных очередь с приоритетом, которая упорядочивает элементы по их естественному порядку или по заданному компаратору. Она представляет собой часть коллекции Java Collections Framework и находится в пакете java.util.

В отличие от Queue, элементы PriorityQueue не упорядочены по времени их добавления, а по приоритету.

Основные методы:

add(E e) - добавляет элемент в очередь.

remove() - удаляет и возвращает элемент с наивысшим приоритетом. Если очередь пуста, генерируется исключение NoSuchElementException.

poll() - удаляет и возвращает элемент с наивысшим приоритетом. Если очередь пуста, возвращает null.

peek() - возвращает, но не удаляет элемент с наивысшим приоритетом. Если очередь пуста, возвращает null.

element() - возвращает, но не удаляет элемент с наивысшим приоритетом. Если очередь пуста, генерируется исключение NoSuchElementException.

Пример:

class Task implements Comparable<Task> {
String name;
Integer priority;

public Task(String name, Integer priority) {
this.name = name;
this.priority = priority;
}

@Override
public int compareTo(@NotNull Task o) {
return priority - o.priority;
}
}

public class Test {
public static void main(String[] args) {
PriorityQueue<Task> pq = new PriorityQueue<>();

pq.add(new Task("Task1", 1));
pq.add(new Task("Task5", 5));
pq.add(new Task("Task2", 2));
pq.add(new Task("Task4", 4));
pq.add(new Task("Task3", 3));

while (!pq.isEmpty()) {
System.out.println(pq.poll().name);
// Выведет: Task1, Task2, Task3, Task4, Task5
}
}
}


#java #PriorityQueue
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10