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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Java Pattern Matching для instanceof: Прощай, лишний каст!

Если вы пишете на Java давно, у вас наверняка выработался рефлекс: сначала проверить тип через instanceof, а потом тут же сделать явное приведение (cast).

Начиная с Java 16, мы можем забыть про эту рутину.

Как мы писали раньше:

Object obj = "Hello World";

if (obj instanceof String) {
String s = (String) obj; // 🤢 Лишняя строка и дублирование типа
System.out.println(s.toUpperCase());
}


Как писать теперь (Pattern Matching):

if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}


🧪 В чем магия?
Вы объявляете переменную (s) прямо в проверке. Если obj действительно является строкой, Java автоматически приводит тип и кладет результат в s. Эта переменная доступна внутри блока if.

🚀 Уровень PRO:
Вы можете использовать созданную переменную в том же условии!

if (obj instanceof String s && s.length() > 5) {
System.out.println("Длинная строка: " + s);
}


Это мелочь, но она убирает тонны визуального шума из кода, особенно в методах equals() или при обработке разнородных данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍51🔥1
⌨️ Switch в Java: Забудьте про break!

Помните старый switch, который мы все тихо ненавидели? Громоздкий синтаксис, необходимость писать break в каждом кейсе и страх случайно провалиться в следующий блок (fall-through).

Начиная с Java 14, у нас есть Switch Expressions. Это не просто косметика, это превращение инструкции в выражение.

💀 Как было (скучно и опасно):

int days = 0;
switch (month) {
case FEBRUARY:
days = 28;
break; // Забыл break? Получи баг!
case APRIL:
case JUNE:
days = 30;
break;
default:
days = 31;
}


➡️ Как стало (элегантно):

int days = switch (month) {
case FEBRUARY -> 28;
case APRIL, JUNE -> 30;
default -> 31;
};


Что изменилось?

1️⃣ Стрелочный синтаксис (->): Код справа от стрелки выполняется только для этого кейса. Никаких break больше не нужно!

2️⃣ Возврат значения: Теперь switch может возвращать результат, который можно сразу присвоить переменной.

3️⃣ Несколько условий: Можно перечислять кейсы через запятую (case APRIL, JUNE).

4️⃣ Слово yield: Если логика сложная и нужен многострочный блок кода, для возврата значения используется yield (вместо return).


int result = switch (input) {
case "A" -> 1;
case "B" -> {
System.out.println("Вычисляем...");
yield 2;
}
default -> 0;
};


Код становится компактнее, безопаснее и понятнее.
Please open Telegram to view this post
VIEW IN TELEGRAM
8🔥5👍2
🚀 Spring Boot: проект за 1 час без боли и конфигураций

Spring Boot — это когда ты запускаешь продовый сервис быстрее, чем успеешь сделать себе чай.
Никаких XML, минимум настроек, встроенный сервер, автоконфигурация и готовые стартовые зависимости.
Вот как собрать рабочий backend за 1 час — от нуля до API.

⚙️ 1. Подключаем зависимости

build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'org.postgresql:postgresql'
}

➡️ Web, валидация, JPA и PostgreSQL — базовый набор для любого сервиса.

▶️ 2. Запускаем приложение

Main-класс:
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

➡️ Встроенный Tomcat поднимется сам.
Никаких конфигов, никакого сервера руками.

🌐 3. Первый REST-контроллер
@RestController
@RequestMapping("/api/hello")
public class HelloController {

@GetMapping
public Map<String, String> hello() {
return Map.of("message", "Spring Boot работает!");
}
}

➡️ Уже есть API, уже можно дёргать в Postman.

🗄 4. Настрока БД

application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/demo
username: user
password: pass
jpa:
hibernate:
ddl-auto: update
show-sql: true

➡️ Spring Boot сам создаёт таблицы, коннектится и логирует SQL.

📦 5. Сущность + репозиторий
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String name;
}


public interface UserRepo extends JpaRepository<User, Long> {}

➡️ CRUD готов без единой строчки SQL.

🧩 6. Сервисный слой
@Service
@RequiredArgsConstructor
public class UserService {

private final UserRepo repo;

public User create(String name) {
var user = new User();
user.setName(name);
return repo.save(user);
}
}

➡️ Чистая логика, никаких репозиторных костылей в контроллере.

🎯 7. API для создания пользователя
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController {

private final UserService service;

@PostMapping
public User create(@RequestParam String name) {
return service.create(name);
}
}

➡️ Post → сохраняем → возвращаем — 30 секунд работы.

🧪 8. Тестируем без сервера
@WebMvcTest(UserController.class)
class UserControllerTest {

@Autowired MockMvc mvc;

@Test
void testCreate() throws Exception {
mvc.perform(post("/api/users?name=Tom"))
.andExpect(status().isOk());
}
}

➡️ MockMvc поднимает только Web-слой, работает молниеносно.

📦 9. Создаём fat-jar и запускаем
./gradlew bootJar
java -jar build/libs/app.jar

➡️ Внутри — сервер, конфиги, код. Готово для деплоя.

☁️ 10. Dockerfile на 5 строк
FROM eclipse-temurin:21
COPY build/libs/app.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]

➡️ Легко уезжает в Kubernetes, AWS, GCP, куда хочешь.


🗣️ Запомни:Spring Boot — это не «фреймворк», а ускоритель: он убирает рутину, чтобы ты писал только логику, а не конфигурационный ад.
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍3🔥2👾1
☕️ Spring AI: LLM прямо внутри твоего Java-сервиса

Никаких отдельных пайплайнов, очередей и костылей.
Spring AI даёт готовый слой для работы с LLM: модели, промпты, memory, embeddings — всё как в Python, только нативно для Java.

⚙️ 1. Подключаем Spring AI

build.gradle
dependencies {
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
}

➡️ Starter тащит автоконфигурацию, модельный клиент и готовые бинды.

🔑 2. Настройка доступа к модели

application.yml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-4.1

➡️ Осталось только дернуть bean — Spring сам соберёт клиент.

💬 3. Генерация ответа из Java-кода
@RestController
@RequiredArgsConstructor
public class AiController {

private final ChatClient chatClient;

@GetMapping("/explain")
public String explain(@RequestParam String code) {
return chatClient
.prompt("Объясни этот код кратко:\n" + code)
.call()
.content();
}
}

➡️ ChatClient → prompt → call().
Минимум связующей логики.

🧩 4. Структурированный вывод (JSON → Java)
record Result(String summary, int score) {}

var response = chatClient
.prompt("""
Проанализируй текст.
Верни: summary, score (0-10).
""")
.responseAs(Result.class);

➡️ LLM сразу мапится в твой record-класс.
Никаких JSON-ручек.

📚 5. Prompts как ресурсы
@AiClient
public interface ReviewAi {

@SystemPrompt("prompts/system.txt")
@UserPrompt("prompts/review.txt")
String analyze(String text);
}

➡️ Промпты лежат в папке, модель вызывается как обычный Java-метод.

🔍 6. Embeddings для поиска
var embedding = embeddingClient.embed("Spring AI makes Java smart");

vectorStore.add("doc-1", embedding);

➡️ Vector store — часть Spring AI: Chroma, PGVector, Redis.
Подходит для RAG в микросервисах.

🧠 7. RAG: ответ с учётом своих данных
var answer = ragClient
.query("Как работает наш биллинг?")
.call()
.content();

➡️ ragClient сам:
1. берёт эмбеддинг вопроса,
2. ищет релевантные документы,
3. подаёт всё в LLM.


🪢 8. Streaming-ответы (chunk за chunk’ом)
chatClient
.prompt("Сгенерируй длинное объяснение")
.stream()
.forEach(chunk -> System.out.print(chunk.content()));

➡️ Нужен, если делаешь real-time UI или аналитический сервис.

🔌 9. Используем несколько моделей одновременно
spring:
ai:
clients:
local:
base-url: http://localhost:1234/v1
chat:
model: llama3
openai:
api-key: ${KEY}
chat:
model: gpt-4.1

➡️ Можно запрашивать локальную LLaMA и облачную OpenAI в одном приложении.

🧵 10. Memory (контекст диалога)
chatClient
.withConversation("session-42")
.prompt("Продолжи диалог")
.call();

➡️ Хранит состояние переписки без твоих ручных костылей.

🗣️ Запомни:Spring AI — это мост между классическим Java-стеком и LLM-миром: минимум клея, максимум интеграций, всё по-джавовски строго и предсказуемо.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥82👍1🥰1
⌨️ HashMap и TreeMap: Когда и как использовать

В Java коллекции Map предоставляют возможность хранить пары "ключ-значение". Два популярных варианта — HashMap и TreeMap. Давайте разберем их ключевые особенности и когда их лучше использовать.

📚 Kраткие определения:

- HashMap:
  - Неупорядоченная коллекция.
  - Основан на хэш-таблице.

- TreeMap:
  - Упорядоченная коллекция.
  - Основан на красно-черном дереве.
  - Поддерживает сортировку по ключам.

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

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

- TreeMap:
  - Если необходимо хранить элементы в отсортированном порядке.
  - Для использования функционала "примитивного" поиска (например, firstKey() или lastKey()).

📌 Подведение итогов:

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

#java #HashMap #TreeMap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
Напоминаем про наш канал с тестами по Java ⌨️
Самое время проверить свои знания и понять, что стоит подтянуть.
➡️ Java | Tests
Please open Telegram to view this post
VIEW IN TELEGRAM
2
⌨️ Java Collection Factories: List.of и Map.of

Если вы пишете на Java дольше 5 лет, вы помните эту боль. Вам просто нужно создать Map с двумя значениями. Но Java требовала от вас целый ритуал.

🐢 Как это было раньше (Java 8 и старее):

// Для списка:
List<String> list = Arrays.asList("a", "b", "c");
// Вроде ок, но этот список можно менять (set), но нельзя менять размер (add/remove).

// Для Map — вообще ужас:
Map<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("two", 2);
map = Collections.unmodifiableMap(map); // Если хотим защитить от изменений


🚀 Как это делается с Java 9:

List<String> list = List.of("a", "b", "c");

Map<String, Integer> map = Map.of("one", 1, "two", 2);

Set<String> set = Set.of("a", "b", "c");


Преимущества:

1️⃣ Неизменяемость (Immutability): Эти коллекции нельзя менять. Попытка сделать .add() или .put() сразу выбросит UnsupportedOperationException. Это делает код безопаснее (особенно в многопоточности).

2️⃣ Лаконичность: Map создается в одну строку (до 10 пар ключ-значение можно писать через запятую, дальше — через Map.ofEntries).

3️⃣ Никаких null: Если вы попытаетесь положить null в List.of или Map.of, вы сразу получите ошибку. Java приучает нас не использовать null в коллекциях.

💡 Лайфхак для Java 16+:
Если вы работаете со стримами, забудьте про .collect(Collectors.toList()).
Теперь можно писать просто:

List<String> result = stream.filter(s -> s.length() > 3).toList();


Обратите внимание: toList() возвращает неизменяемый список, в отличие от коллектора.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥72👍2🤷‍♂1
⌨️ Sealed Classes: Фейсконтроль для наследования

В ООП всегда была дилемма.
Если вы делаете класс public, от него может наследоваться кто угодно.
Если делаете final, от него не может наследоваться никто.

А что, если я хочу, чтобы от моего класса Payment могли наследоваться только CashPayment и CardPayment, и больше никто?

До Java 17 приходилось придумывать костыли с пакетами. Теперь у нас есть Sealed Classes (Запечатанные классы).

✔️ Как это работает:
Вы используете ключевое слово sealed и через permits перечисляете, кому "можно".

public sealed interface Shape permits Circle, Square, Rectangle {
// Общие методы
}


Теперь Java (и компилятор) гарантирует: никаких других фигур, кроме этих трех, в программе существовать не может.

➡️ Правила игры:
Наследники (Circle, Square...) должны выбрать свою судьбу и указать один из модификаторов:

1️⃣ final — от меня наследовать нельзя (конец цепочки).

2️⃣ sealed — я тоже строгий, вот мой список наследников.

3️⃣ non-sealed — ладно, от меня можно наследовать всем (открываем шлюз).

🔥 Зачем это нужно? (Главная фишка)
Это идеально работает в связке с новым Switch.
Поскольку компилятор точно знает все возможные варианты наследников, он не потребует от вас ветку default!


String result = switch (shape) {
case Circle c -> "Это круг радиусом " + c.radius();
case Square s -> "Это квадрат";
case Rectangle r -> "Это прямоугольник";
// default не нужен! Java знает, что других фигур нет.
};


Это делает моделирование бизнес-логики (статусы заказов, типы ошибок) невероятно надежным. Если вы добавите новую фигуру, код перестанет компилироваться, пока вы не обработаете её в свитче.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍3❤‍🔥11😁1
⌨️ Sequenced Collections: Конец мучений с list.get(size - 1)

Признайтесь, сколько раз за свою карьеру вы писали этот уродливый код, чтобы достать последний элемент списка?

😫 Старая школа (до Java 21):

var list = List.of("A", "B", "C");

// Чтобы взять последний элемент:
String last = list.get(list.size() - 1);

// А если это Set? (LinkedHashSet)
// Приходилось использовать итератор или перегонять в список... 😱
String lastInSet = set.iterator()... // Ой, всё, лень писать.


Это было неудобно, нечитаемо и чревато ошибками (привет, -1).

🥳 Java 21 (Sequenced Collections):
В Java наконец-то добавили общий интерфейс для всех коллекций, у которых есть порядок элементов — SequencedCollection.

Теперь у List, Deque, SortedSet и LinkedHashSet появились единые методы:

list.getFirst(); // Взять первый
list.getLast(); // Взять последний (Наконец-то!)

list.addFirst("Z"); // Добавить в начало
list.addLast("X"); // Добавить в конец

list.reversed(); // Получить представление коллекции в обратном порядке


🔥 Почему это круто?

1️⃣ Единый стандарт. Раньше у Deque были методы getFirst, у Listget(0), у SortedSetfirst(). Теперь везде одинаково.

2️⃣ Работает с Set. Теперь можно легко взять первый или последний элемент из LinkedHashSet или TreeSet, не прибегая к итераторам.

3️⃣ Безопасность типов. Метод reversed() возвращает «живое» представление. Изменения в нем отразятся на оригинале (для мутабельных коллекций).

Вроде мелочь, а код становится намного чище.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍51
🔥 БЕСПЛАТНЫЙ КУРС ПО СОЗДАНИЮ НЕЙРО-СОТРУДНИКОВ НА GPT И ДРУГИХ LLM 🔥

Ищете практический и углубленный курс, чтобы освоить создание нейро-сотрудников? Мы создали курс из 5 объемных занятий. Это именно то, что нужно, чтобы прокачать свои навыки абсолютно бесплатно!

📌 Темы занятий:
1. Введение в мир нейро-сотрудников
2. Как работают LLM и их аналоги
3. Создание базы знаний для нейро-сотрудника (RAG)
4. Тестирование и отладка нейро-сотрудников
5. Интеграция нейро-сотрудников в Production

Вот 5 тем курса - он максимально простой и доступный, общеобразовательный, без какого-либо сложного программирования 📚Прохождение этого курса, скорее всего, займет у вас от 1 до 3 часов

🤖 Присоединяйтесь к нашему бесплатному курсу и разберитесь в этой увлекательной теме с нами!
1🔥1
⌨️ Java Unnamed Variables: Сила символа _

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

😒 Как мы выкручивались раньше:
Приходилось придумывать имя переменной, чтобы компилятор был доволен, а потом IDE ругалась: "Variable 'e' is never used".

try {
int number = Integer.parseInt(input);
} catch (NumberFormatException e) { // <-- Зачем нам 'e'?
// Мы и так знаем, что это не число, детали ошибки нам не важны
System.out.println("Это не число!");
}


Или в циклах:

for (var s : list) { // <-- Нам нужно просто посчитать количество, 's' не нужна
count++;
}


Как стало с Java 22 (Unnamed Variables):
Теперь можно использовать символ подчеркивания _. Это сигнал компилятору: "Здесь должна быть переменная, но я не собираюсь её использовать".

try {
int number = Integer.parseInt(input);
} catch (NumberFormatException _) { // Красота!
System.out.println("Это не число!");
}


Или в паттерн-матчинге (для instanceof и switch), если нам важен только тип, а не само значение:

if (obj instanceof String _) {
System.out.println("Да, это строка (но читать её я не буду)");
}


🔥 Почему это круто?

1️⃣ Чистота намерений: Читая код, другой разработчик сразу понимает: эта переменная игнорируется намеренно, а не по ошибке.

2️⃣ Спокойствие IDE: Анализаторы кода больше не спамят предупреждениями "Unused variable".

3️⃣ Меньше когнитивной нагрузки: Не нужно придумывать имена вроде ignored, unused или dummy.
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍2