JUnit 5 — это не просто
@Test. Он принёс гибкость, читаемость и мощные возможности для модульного тестирования.Вот мини-шпаргалка по ключевым аннотациям, которые ты реально будешь использовать.
1.
@Test — запуск теста@Test
void shouldReturnTrueWhenInputIsValid() {
assertTrue(MyService.validate("test"));
}
2.
@BeforeEach и @AfterEach — подготовка и очистка@BeforeEach
void init() {
db.connect();
}
@AfterEach
void cleanup() {
db.disconnect();
}
3. 🏗
@BeforeAll и @AfterAll — один раз на весь класс@BeforeAll
static void globalSetup() {
System.out.println("Запускаем все тесты");
}
4.
@DisplayName — читаемое имя теста@DisplayName("Должен вернуть true при корректном email")
@Test
void validEmailTest() {
assertTrue(EmailValidator.isValid("test@example.com"));
}5.
@Nested — группировка тестов@Nested
class WhenUserIsAdmin {
@Test
void shouldHaveFullAccess() { ... }
}
6.
@ParameterizedTest + @ValueSource — параметризованные тесты@ParameterizedTest
@ValueSource(strings = {"admin", "user", "guest"})
void roleShouldNotBeNull(String role) {
assertNotNull(role);
}
7.
@Disabled — временно отключить тест@Disabled("Фича ещё не реализована")
@Test
void futureFeatureTest() {
fail("не должно запускаться");
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍6❤🔥1🔥1
stream().map().filter().collect() — читаемо и мощноJava Stream API — это как
grep | awk | sort в Linux, только в Java-стиле.Самая частая связка: map → filter → collect. И она может заменить кучу шаблонного кода.
Допустим, у нас есть список:
List<String> names = List.of("Alice", "bob", "CHARLIE", "dave");До Stream API:
List<String> result = new ArrayList<>();
for (String name : names) {
String upper = name.toUpperCase();
if (upper.length() > 3) {
result.add(upper);
}
}
С
stream():List<String> result = names.stream()
.map(String::toUpperCase)
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
1. `map()` — преобразование
.map(String::trim)
.map(String::toLowerCase)
2. `filter()` — отбор
.filter(s -> s.startsWith("a"))
3. `collect()` — сборка результата
.collect(Collectors.toSet())
.collect(Collectors.joining(", "))
🧺 Собирает результат обратно в список, множество, строку и т.д.
List<User> users = getUsers();
List<String> activeAdults = users.stream()
.filter(User::isActive)
.filter(u -> u.getAge() >= 18)
.map(User::getName)
.collect(Collectors.toList());
if, for и add() — код фокусируется на логике, а не на реализации.map().filter().collect() — это про читаемый и декларативный код.Не пиши как императивный робот, пиши как человек: что ты хочешь получить — а не как это сделать.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤3🔥2👨💻1
final в Java — стоп-сигнал для измененийВ Java
final — это как «не трогай»: запрет на изменение.Но что именно он запрещает? Всё зависит от того, где его поставить: переменная, метод, класс.
Разберёмся
1.
final переменные — нельзя переназначитьfinal int port = 8080;
port = 9090; // ❌ ошибка компиляции
final List<String> list = new ArrayList<>();
list.add("Hello"); // ✅ можно
list = new ArrayList<>(); // ❌ нельзя
final не делает объект неизменяемым. Только ссылку.2.
final методы — нельзя переопределить в наследникахclass Animal {
final void sleep() {
System.out.println("Zzz...");
}
}
class Dog extends Animal {
// ❌ Нельзя переопределить sleep()
}3.
final классы — нельзя наследовать вообщеfinal class Utility {
static void log(String msg) { ... }
}class MyUtil extends Utility {} // ❌ ошибкаMath, String)SecurityManager, System)final аргументы в методах → защищает от случайного переназначенияfinal поля + @Immutable → хорошая практика для DTOfinal классы → в record, enum, String, LocalDate и т.д.final = контроль. Это способ сказать «вот это трогать нельзя». Используй его осознанно — чтобы сделать поведение предсказуемым и безопасным.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3👨💻2❤1
До Java 13 работа с многострочными строками была болью. JSON? HTML? SQL? Только через
"\n" + и кучу экранирования.Но с Text Blocks всё стало проще, понятнее и читаемо.
Сравни:
String html = "<html>\n" +
" <body>Hello</body>\n" +
"</html>";
String html = """
<html>
<body>Hello</body>
</html>
""";
String, просто оформленная красиво.Text Blocks:1.
Код больше не превращается в кашу. Особенно полезно для:
SQL-запросов:
String query = """
SELECT id, name
FROM users
WHERE active = true
ORDER BY created_at DESC
""";
HTML/JSON шаблонов:
String json = """
{
"name": "Alice",
"role": "admin"
}
""";
2.
Забудь про
\", \\n, \\t — теперь можно писать почти как в блокноте.3.
Java сама уберёт начальные отступы на основе самой "узкой" строки.
Пример:
String msg = """
Line 1
Line 2
Line 3
""";
Line 1
Line 2
Line 3
4.
.formatted() Нельзя вставить переменные прямо в Text Block?
Используем .formatted() — коротко и читабельно:
String user = "Bob";
String template = """
{
"user": "%s",
"access": "granted"
}
""".formatted(user);
````
```java
String s = """
Hello""";
System.out.println(s.length()); // 6, а не 5 (есть \n)
3.
Нельзя писать так:
String name = "Eve";
String wrong = """
Hello, $name!
"""; // ❌ не сработает
Вместо этого:
String right = """
Hello, %s!
""".formatted(name);
+ "\n".Please open Telegram to view this post
VIEW IN TELEGRAM
❤18👍4👨💻2🔥1
Factory-паттерн — это способ создавать объекты, не раскрывая логику создания. Но в Java он часто обрастает шаблонами, абстракциями и XML'ем. Зачем? Можно проще.
Допустим, у нас есть интерфейс:
interface Notification {
void send(String message);
}И реализации:
class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
class SmsNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}class NotificationFactory {
public static Notification create(String type) {
return switch (type) {
case "email" -> new EmailNotification();
case "sms" -> new SmsNotification();
default -> throw new IllegalArgumentException("Unknown type");
};
}
}Использование:
Notification n = NotificationFactory.create("email");
n.send("Hello world!");1.
Меняем реализацию в одном месте.
2.
Можно возвращать любые классы — хоть анонимные, хоть лямбды.
3.
Никаких XML, DI-фреймворков и пяти уровней абстракции.
1.
Если
new работает — не трогай.2.
Часто
enum c фабрикой — читается лучше, чем строки.Please open Telegram to view this post
VIEW IN TELEGRAM
👍19❤4🔥3
@Cacheable — быстро и просто в SpringКогда метод тяжёлый (долго считает, лезет в БД или API) — зачем вызывать его 100 раз, если результат тот же?
Решение: кеш. В Spring это делается одной аннотацией.
@Cacheable?Она сохраняет результат метода в кеш.
При повторном вызове с теми же аргументами — возвращает значение из кеша, не запуская метод снова.
@Cacheable("users")
public User getUserById(Long id) {
System.out.println("Fetching from DB...");
return userRepository.findById(id).orElseThrow();
}Первый вызов: метод выполнится → результат кешируется.
Следующие вызовы с тем же
id: результат берётся из кеша.1. Добавь зависимость (если ещё нет):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2. Включи кеш в
@Configuration:@EnableCaching
@SpringBootApplication
public class MyApp { }
Spring по умолчанию использует простой in-memory кеш (ConcurrentHashMap), но можно подключить Caffeine, Redis, Ehcache и т.д.
🎯 Ключ кеша по полям:
@Cacheable(value = "products", key = "#category + ':' + #limit")
public List<Product> getTopProducts(String category, int limit) { ... }
@Cacheable(value = "data", unless = "#result == null")
public Data fetchData(String key) { ... }
@CachePut("users")
public User updateUser(User user) { ... }🧹 Очистка кеша:
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) { ... }
@Cacheable — это «копим и не дёргаем зря».С ним ты ускоряешь работу приложения без лишнего кода, особенно если есть дорогие вызовы (БД, сеть, парсинг).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤5👌3🔥2
Media is too big
VIEW IN TELEGRAM
Этот курс охватывает основы Java, включая установку JDK, работу с переменными, условными операторами, циклами и объектно-ориентированным программированием. Подходит для тех, кто только начинает знакомство с языком
Please open Telegram to view this post
VIEW IN TELEGRAM
👾2👍1
Object это базовый класс для всех остальных объектов в Java. Любой класс наследуется от Object и, соответственно, наследуют его методы:public boolean equals(Object obj) – служит для сравнения объектов по значению;int hashCode() – возвращает hash код для объекта;String toString() – возвращает строковое представление объекта;Class getClass() – возвращает класс объекта во время выполнения;protected Object clone() – создает и возвращает копию объекта;void notify() – возобновляет поток, ожидающий монитор;void notifyAll() – возобновляет все потоки, ожидающие монитор;void wait() – остановка вызвавшего метод потока до момента пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;void wait(long timeout) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;void wait(long timeout, int nanos) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;protected void finalize() – может вызываться сборщиком мусора в момент удаления объекта при сборке мусора.#java #Object #methods
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
Нужен простой способ понять, какие строки кода вообще исполняются при тестировании?
JaCoCo делает это красиво: запускаешь тесты — получаешь отчёт в HTML с краской по строкам.
В pom.xml добавляешь:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
Теперь просто запускаешь:
mvn clean verify
После этого открой отчёт:
open target/site/jacoco/index.html
Есть метод:
public int divide(int a, int b) {
if (b == 0) throw new IllegalArgumentException("zero");
return a / b;
}Если тесты вызывают только divide(10, 2) — то строка с исключением будет красной (не покрыта).
Значит, ты пропустил случай деления на 0 — тест не полный.
Тесты без покрытия — это как замок на двери без ключа. Видимость есть, защиты нет.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👨💻1
Нужно, чтобы один объект реагировал на изменения другого? Без тайных фреймворков, просто на Java?
Решение — паттерн Наблюдатель (Observer). Он позволяет подписчикам автоматически узнавать об изменениях.
// Observable (Subject)
class NewsAgency {
private List<NewsListener> listeners = new ArrayList<>();
public void addListener(NewsListener l) {
listeners.add(l);
}
public void publish(String news) {
for (NewsListener l : listeners) {
l.update(news);
}
}
}
// Observer (Listener)
interface NewsListener {
void update(String news);
}
// Конкретный подписчик
class TelegramBot implements NewsListener {
public void update(String news) {
System.out.println("🔔 Telegram получил: " + news);
}
}
public class Main {
public static void main(String[] args) {
NewsAgency agency = new NewsAgency();
agency.addListener(new TelegramBot());
agency.publish("Java 21 уже вышел!");
agency.publish("🧵 Loom теперь в preview!");
}
}🔔 Telegram получил: Java 21 уже вышел!
🔔 Telegram получил: 🧵 Loom теперь в preview!
Добавь нескольких подписчиков:
class EmailNotifier implements NewsListener {
public void update(String news) {
System.out.println("📧 Email-рассылка: " + news);
}
}agency.addListener(new EmailNotifier());
Теперь все слушатели получают событие одновременно.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18👨💻4❤3🔥1
С 8-й версии Java предлагает мощные инструменты для работы с коллекциями — и пора ими воспользоваться. Забудь про
for и while, когда можно писать элегантно и декларативно.В статье ты найдёшь:
Stream API, которые экономят строки кодаfilter(), map(), collect() и других трюковPlease open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤2❤🔥2👍2
RestTemplate давно знаком, но теперь Spring рекомендует использовать WebClient. Это не просто новый способ сделать HTTP-запросы — это полноценный инструмент, который умеет работать асинхронно, поддерживает реактивность и даёт гораздо больше контроля над процессом.
Вот как выглядит простой GET-запрос:
WebClient client = WebClient.create();
String body = client.get()
.uri("https://api.github.com/users/octocat")
.retrieve()
.bodyToMono(String.class)
.block();
System.out.println(body);
Здесь
bodyToMono(String.class) возвращает реактивный тип Mono, который содержит результат. Если вызвать .block(), запрос будет выполняться синхронно, так что можно легко внедрять WebClient даже в привычный код.Для POST-запроса с телом используем:
WebClient client = WebClient.create("https://httpbin.org");
String response = client.post()
.uri("/post")
.header("Content-Type", "application/json")
.bodyValue("{\"name\":\"PyLinux\"}")
.retrieve()
.bodyToMono(String.class)
.block();
System.out.println(response);Ошибки обрабатываются через
onStatus, например, для 4xx:client.get()
.uri("https://api.github.com/404")
.retrieve()
.onStatus(status -> status.is4xxClientError(), resp -> {
System.out.println("Ошибка клиента: " + resp.statusCode());
return Mono.error(new RuntimeException("Client error"));
})
.bodyToMono(String.class)
.block();
Если нужно передать заголовки или параметры:
WebClient client = WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader("Authorization", "Bearer your_token")
.build();
String data = client.get()
.uri(uriBuilder -> uriBuilder
.path("/data")
.queryParam("limit", 10)
.build())
.retrieve()
.bodyToMono(String.class)
.block();
Таким образом, WebClient позволяет легко делать запросы с любыми параметрами и заголовками, при этом можно управлять асинхронностью и реактивностью без лишних сложностей.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤4❤🔥3💅2🔥1
Media is too big
VIEW IN TELEGRAM
Этот курс объясняет, что такое Project Loom в Java, включая виртуальные потоки, улучшение масштабируемости и новые возможности многозадачности. Подходит для разработчиков, интересующихся современными подходами к многозадачности в Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🔥1
List.of() в Java — быстро, но не всегда безопасноС Java 9 появился удобный способ создать список:
List<String> names = List.of("Alice", "Bob", "Charlie");Выглядит лаконично, работает быстро — но есть нюанс.
List<String> list = List.of("a", "b");
list.add("c"); // 💥 UnsupportedOperationException
list.remove("a"); // 💥 тоже ошибкаЛюбая попытка изменить список — ошибка во время выполнения. Это не
ArrayList, а immutable List.List<String> list = List.of("hello", null); // 💥 NullPointerExceptionДаже один
null — и всё падает. Потому что List.of() не допускает null ни в одном элементе.System.out.println(List.of("a", "b").getClass());
// class java.util.ImmutableCollections$ListNЭто не
ArrayList, не LinkedList. Это внутренний тип, оптимизированный под неизменяемость.Если твой код ждёт
ArrayList и будет кастить — ловишь ClassCastException.List.of(DAYS))null нетList<String> modifiable = new ArrayList<>(List.of("a", "b", "c"));
modifiable.add("d"); // 👍 теперь можноList.of() — круто для коротких, неизменяемых данных.Но если планируешь менять список или есть шанс на
null — лучше явно используй `ArrayList`.Не пались на удобстве — знай, что лежит под капотом.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤5
🧵 Используй try-with-resources с потоками правильно (и продвинуто)
Если ты до сих пор закрываешь потоки руками или думаешь, что try-with-resources — это только для файлов, смотри:
🛠 Пример 1: чтение и закрытие автоматически
☑️ Поток закрывается автоматически — даже если внутри случится исключение.
🧪 Пример 2: кастомный ресурс (любой AutoCloseable)
🧠 Всё, что реализует AutoCloseable, можно оборачивать в try-with-resources. Это не только файлы, но и сетевые соединения, стримы, логи, сессии Hibernate и др.
🕸 Пример 3: несколько ресурсов
🔒 Все ресурсы закроются в обратном порядке.
🗣️ Запомни: try-with-resources — не просто синтаксический сахар. Это способ писать надёжный код без утечек ресурсов и без лишнего шаблонного кода. Особенно полезно при работе с сетью, файлами, базами данных и внешними API.
Если ты до сих пор закрываешь потоки руками или думаешь, что try-with-resources — это только для файлов, смотри:
try (BufferedReader reader = Files.newBufferedReader(Path.of("data.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}public class TempResource implements AutoCloseable {
public void doSomething() {
System.out.println("Работаем с ресурсом");
}
@Override
public void close() {
System.out.println("Ресурс закрыт");
}
}
try (TempResource res = new TempResource()) {
res.doSomething();
}try (
InputStream in = new FileInputStream("input.txt");
OutputStream out = new FileOutputStream("output.txt")
) {
in.transferTo(out);
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍6🔥4
Считаешь Java не для AI? Серьёзно ошибаешься! LangChain, фреймворк для разработки с языковыми моделями, теперь уже доступен и для Java — через LangChain4J.
В статье ты узнаешь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2🔥2👏1
🌀 Pattern Matching в Java — прощай `instanceof + cast`
Раньше, чтобы проверить тип и привести его, писали вот так:
👎 Шумно, опасно, повторяется.
С Java 16+ можно проще и безопаснее — паттерн-матчинг для `instanceof`:
✔️ Как это работает:
✅ Если
Больше никаких ручных кастов.
🛠 Примеры на практике:
☑️ Проверка нескольких типов
🔍 Код стал чище: без каста, без дублирования
🚀 Использование внутри
С Java 21 (preview) можно использовать
➡️ Это называется Pattern Matching for switch.
🧩 Совмещение с guard'ами
⚠️
🧪 Более сложные условия
Можно комбинировать с
🗣️ Запомни: Используй
Раньше, чтобы проверить тип и привести его, писали вот так:
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.toLowerCase());
}С Java 16+ можно проще и безопаснее — паттерн-матчинг для `instanceof`:
if (obj instanceof String s) {
System.out.println(s.toLowerCase());
}obj — String, то переменная s уже приведена к нужному типу.Больше никаких ручных кастов.
void printInfo(Object obj) {
if (obj instanceof String s) {
System.out.println("Строка: " + s.toUpperCase());
} else if (obj instanceof Integer i) {
System.out.println("Число: " + (i * 2));
} else {
System.out.println("Что-то другое");
}
}obj.switchС Java 21 (preview) можно использовать
switch с типами:static String format(Object obj) {
return switch (obj) {
case String s -> "Строка: " + s;
case Integer i -> "Целое: " + i;
case null -> "null";
default -> "Неизвестно";
};
}if (obj instanceof String s && s.length() > 5) {
System.out.println("Длинная строка: " + s);
}s будет доступна только если оба условия выполняются. Это безопасно.if (!(obj instanceof String s)) return;
System.out.println("Обрабатываем строку: " + s.toLowerCase());
Можно комбинировать с
!instanceof, return, continue, break и др.instanceof с привязкой переменной — особенно в if-else, парсерах, логике обработки событий и switch.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤3🔥2👨💻1
Stream API — мощный инструмент, но легко попасть в ловушку, если не знать нюансов.
List<String> names = users.stream()
.filter(u -> u.isActive())
.map(User::getName)
.collect(Collectors.toList());
Map<Long, String> map = users.stream()
.collect(Collectors.toMap(
User::getId,
User::getName,
(a, b) -> a // если дубликат — оставить первый
));
Map<String, List<User>> grouped = users.stream()
.collect(Collectors.groupingBy(User::getRole));
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
// stream.forEach(...) // ❌ выбросит исключение — уже использован
Stream.of("a", "b", "c")
.filter(s -> {
System.out.println("filter: " + s);
return true;
});
// ничего не произойдёт, пока не вызвать .collect() или .forEach()Stream.of("a", null, "b"); // ❌ NPE при map/filterЛучше фильтровать:
Stream.of("a", null, "b")
.filter(Objects::nonNull)
.map(String::toUpperCase)
.forEach(System.out::println);Фильтруем активных, сортируем по дате, берём 10 последних:
List<Post> recent = posts.stream()
.filter(Post::isActive)
.sorted(Comparator.comparing(Post::getCreatedAt).reversed())
.limit(10)
.collect(Collectors.toList());
Всегда помни про однократность, лень и null — и всё будет летать.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤6🔥2❤🔥1
Используешь Stream в Java 8+? Только не думай, что это всегда просто и быстро. В этой статье — реальные кейсы и трюки, которые позволят ускорить обработку коллекций и избежать типичных ошибок.
В статье ты узнаешь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1