
- Главная
- Каталог
- Интернет технологии
- Java | Фишки и трюки
Java | Фишки и трюки
Аудитория канала - начинающие или опытные Java программисты. Канал о разработке приложений на Java, в том числе написание бэкенд и web-приложений. Рассматриваются фишки и трюки при программировании на Java.
Статистика канала
import java.lang.reflect.Method;
public class Calculator {
private int superSecretFormula(int a, int b) {
return (a + b) * (a - b);
}
}
// В тесте:
Method method = Calculator.class.getDeclaredMethod("superSecretFormula", int.class, int.class);
method.setAccessible(true); // Взламываем приватность
int result = (int) method.invoke(new Calculator(), 5, 3);{}
1. Выполняет несколько задач (нарушает SRP). 2. Содержит логику, которая может пригодиться где-то ещё. 3. Слишком умный для своего класса.
public class ReportService {
public String generateReport() {
// ... подготовка данных
String cleaned = cleanData(rawData); // приватный метод
// ... формирование отчёта
}
private String cleanData(String data) {
// сложная логика очистки
}
}{}
// Новая публичная единица, которую легко тестировать
public class DataCleaner {
public String clean(String data) {
// та же логика, но теперь она публичная
}
}
// В ReportService:
public class ReportService {
private final DataCleaner cleaner;
public String generateReport() {
String cleaned = cleaner.clean(rawData);
// ...
}
}{}
DataCleaner можно и нужно тестировать напрямую. Это чистая архитектура.
// Было: private void helper() { ... }
// Стало (в том же пакете):
class Service {
void helper() { ... } // без модификатора = виден в пакете
}
// В тестах (которые лежат в том же test/java/... пакете):
@Test
void testHelper() {
Service service = new Service();
service.helper(); // Доступно!
}{}
@Test
void generateReport_usesCleanDataLogic() {
ReportService service = new ReportService();
String report = service.generateReport();
assertThat(report).contains("очищенные данные");
}{}
@SneakyThrows в Lombok: как она обманывает компилятор
Когда видишь @SneakyThrows, кажется, что нашёл волшебную палочку: checked-исключения больше не нужно объявлять в throws и ловить в try-catch. Но эта магия — не настоящее волшебство, а тонкая иллюзия, которая может сломать твой код в самый неподходящий момент.
Давай заглянем под капот и узнаем, как эта аннотация обманывает компилятор, и почему с ней нужно быть осторожным
// Без Lombok: нужно либо пробросить, либо поймать
public void readFile() throws IOException { // Объявляем throws
Files.readAllBytes(Paths.get("file.txt"));
}
// Или так:
public void readFile() {
try {
Files.readAllBytes(Paths.get("file.txt"));
} catch (IOException e) { // Ловим исключение
throw new RuntimeException(e);
}
}{}
import lombok.SneakyThrows;
public class FileReader {
@SneakyThrows
public byte[] readFile() {
return Files.readAllBytes(Paths.get("file.txt"));
}
}{}
throws, никакого try-catch! Код компилируется, и ты можешь вызывать метод, как будто исключений не существует. Но они никуда не делись.
public byte[] readFile() {
try {
return Files.readAllBytes(Paths.get("file.txt"));
} catch (IOException e) {
throw Lombok.sneakyThrow(e); // Вот этот метод — ключ!
}
}
// А метод sneakyThrow делает вот что:
public static RuntimeException sneakyThrow(Throwable t) {
throw Lombok.<RuntimeException>sneakyThrow0(t);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
throw (T) t; // Кастование к unchecked-исключению!
}{}
@SneakyThrows
public void connect() {
Socket socket = new Socket("host", 9999); // Может кинуть IOException
// ... работа с сокетом
}
// Где-то в другом месте:
public void init() {
connect(); // Код не знает, что здесь возможен IOException!
// И поэтому не готов его обработать
}{}
// Попробуем использовать в лямбде (Consumer)
list.forEach(element -> {
@SneakyThrows
Thread.sleep(100); // Так не сработает!
});
// Нужно отдельно выносить:
list.forEach(this::sneakySleep);
@SneakyThrows
private void sneakySleep(Object element) {
Thread.sleep(100);
}{}
@SneakyThrows не работает прямо на лямбдах. Это ограничивает его применение.
Runnable).
3. Для избежания излишнего обертывания в RuntimeException, когда ты точно уверен в поведении метода.
// Пример с Runnable
public class Worker implements Runnable {
@SneakyThrows
@Override
public void run() {
Files.readAllBytes(Paths.get("config.json")); // IOException будет проброшен как unchecked
}
}{}
@SneakyThrows - это не решение, а побег из тюрьмы checked-исключений через подкоп.Optional.ofNullable() - как не стрелять себе в ногу NullPointerException
Кажется, что Optional должен спасать от null. Но если перепутать Optional.of() с Optional.ofNullable() - получишь NPE там, где меньше всего ожидал. Это как заряжать пистолет, думая, что он игрушечный.
Вот разбор, как не попасть в эту ловушку и когда что использовать
// Если value == null, то:
Optional.of(value); // 🚨 Выбросит NPE
Optional.ofNullable(value); // ✅ Вернёт Optional.empty(){}
Optional.of создаёт контейнер только для не-null значений. Optional.ofNullable - для любых, сам проверит и сделает empty() при null.
null, а ты оборачиваешь результат в Optional для красоты:
String findNameById(Long id) {
// ... какой-то поиск, который может вернуть null
}
// Где-то в коде:
Optional<String> name = Optional.of(findNameById(42)); // БАМ! NPE{}
of() выстрелит раньше, чем ты успеешь его использовать. Типичная ошибка при рефакторинге старого кода.
// Входящее значение может быть null -> только ofNullable
Optional<String> safeName = Optional.ofNullable(findNameById(42));
// Теперь можно безопасно работать
String result = safeName.orElse("По умолчанию");{}
ofNullable - это шлюз, который пропускает и null, и значение, превращая первое в empty().
null. Например:
// Константы, финальные строки
Optional<String> env = Optional.of("PROD");
// Результаты методов, которые никогда не возвращают null по контракту
Optional<String> uuid = Optional.of(UUID.randomUUID().toString());{}
of() как assertion - «это точно не null». Если сомневаешься - ofNullable.
public Optional<String> extract(boolean flag) {
String value = flag ? "Java" : null;
return Optional.of(value); // Что будет при flag = false?
}{}
Optional. Эту ошибку компилятор не подскажет.
Optional.of() - это крик «я уверен!». Если не готов ловить NPE, как пулю, всегда используй ofNullable.В этом видео автор переходит от консольных проектов к созданию графических интерфейсов. Вы научитесь разрабатывать полноценное ПК-приложение с использованием библиотеки Java Swing, добавляя в него кнопки, надписи, текстовые поля и другие графические компоненты на основе JFrame.
String.format() StringBuilder — кто быстрее на самом деле?
Каждый день ты склеиваешь строки. Но если это происходит в горячем цикле или в высоконагруженном микроссервисе — разница в подходах может стоить миллисекунд, а то и секунд процессорного времени. Давай расставим всё по местам с цифрами в руках.
Вот бенчмарк-ликбез, после которого ты больше не будешь гадать
// 1. Конкатенация (+)
String result1 = "Привет, " + name + "! Тебе " + age + " лет.";
// 2. StringBuilder
String result2 = new StringBuilder()
.append("Привет, ")
.append(name)
.append("! Тебе ")
.append(age)
.append(" лет.")
.toString();
// 3. String.format()
String result3 = String.format("Привет, %s! Тебе %d лет.", name, age);
// 4. String.concat() (редко, но бывает)
String result4 = "Привет, ".concat(name).concat("! Тебе ").concat(String.valueOf(age)).concat(" лет.");{}
Конкатенация (+) ........... ~50 нс
StringBuilder .............. ~15 нс
String.format() ............ ~1200 нс
String.concat() ............ ~70 нс{}
String.format() проигрывает в скорости в десятки раз. Он делает парсинг шаблона, проверку типов — это дорого. StringBuilder — чемпион по скорости.
// Ты пишешь:
String s = a + b + c;
// Компилятор делает под капотом:
String s = new StringBuilder().append(a).append(b).append(c).toString();{}
// ❌ ПЛОХО (создаётся новый StringBuilder на КАЖДОЙ итерации)
String result = "";
for (String part : parts) {
result += part; // Скрытый new StringBuilder() каждый раз!
}
// ✅ ХОРОШО (один StringBuilder на весь цикл)
StringBuilder sb = new StringBuilder();
for (String part : parts) {
sb.append(part);
}
String result = sb.toString();{}
// Читаемо vs Нечитаемо
String.format("Сумма: %.2f руб., дата: %tD", sum, date); // ✅
// vs ручное склеивание с DecimalFormat и SimpleDateFormat — кошмар
{}
2. Логирование, где скорость не критична (но даже там лучше шаблонизатор).
3. Конфигурационные сообщения, выносимые в properties-файлы.
String.format() — это Rolls-Royce: удобно, красиво, но для поездки в магазин за хлебом — избыточно.
// Когда нужно собрать строку через разделитель
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("Java");
joiner.add("Kotlin");
joiner.add("Scala");
String result = joiner.toString(); // [Java, Kotlin, Scala]{}
StringBuilder, но даёт элегантный API для склейки с разделителями. Используй вместо ручных проверок «не первый ли элемент?».
java.util.Date должен умереть
В старых версиях Java работа со временем была настоящим квестом. Класс java.util.Date — это, пожалуй, самый неудачный дизайн в истории JDK.
🤦♂️ Зал славы проблем Date и Calendar:
1️⃣ Они изменяемые (Mutable): Вы передаете дату в метод, а он может тихо поменять ей год. Это ад для многопоточности.
2️⃣ Нумерация месяцев: Январь — это 0. Декабрь — 11. Сколько багов было написано из-за этого!
3️⃣ Годы: new Date(2023, ...) создаст дату в 3923 году (потому что отсчет идет с 1900).
4️⃣ Нейминг: java.sql.Date наследуется от java.util.Date, но не содержит времени. Путаница неизбежна.
✅ Спасение в Java 8+ (java.time)
Java переняла опыт библиотеки Joda-Time и внедрила JSR 310. Теперь у нас есть строгие, неизменяемые и понятные типы.
Шпаргалка, что выбрать:
1️⃣ Instant — Точка на временной шкале (Unix Timestamp).
Для кого: Для машин, логов и баз данных. Внутри это просто количество секунд с 1970 года (UTC).
Пример: Instant.now()
2️⃣ LocalDate / LocalTime — "Дата в календаре" и "Время на часах". Без часового пояса.
Для кого: Дни рождения, праздники ("Новый год всегда 1 января", неважно, где вы).
Пример: LocalDate.of(2023, Month.JANUARY, 1)
3️⃣ ZonedDateTime — Полный фарш: дата + время + часовой пояс.
Для кого: Для организации встреч звонков между странами. Учитывает переход на летнее время!
💎 Неизменяемость (Immutability):
Больше никаких сюрпризов. Методы изменения времени всегда возвращают новый объект.
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1); // today остался прежним!
{}
💡 Лайфхак:
Если вам нужно посчитать разницу между датами, используйте Period (для дней/месяцев) или Duration (для секунд/наносекунд).
long days = ChronoUnit.DAYS.between(date1, date2);{}
Отзывы канала
всего 11 отзывов
- Добавлен: Сначала новые
- Добавлен: Сначала старые
- Оценка: По убыванию
- Оценка: По возрастанию
Каталог Телеграм-каналов для нативных размещений
Java | Фишки и трюки — это Telegam канал в категории «Интернет технологии», который предлагает эффективные форматы для размещения рекламных постов в Телеграмме. Количество подписчиков канала в 7.1K и качественный контент помогают брендам привлекать внимание аудитории и увеличивать охват. Рейтинг канала составляет 19.5, количество отзывов – 11, со средней оценкой 5.0.
Вы можете запустить рекламную кампанию через сервис Telega.in, выбрав удобный формат размещения. Платформа обеспечивает прозрачные условия сотрудничества и предоставляет детальную аналитику. Стоимость размещения составляет 2237.76 ₽, а за 86 выполненных заявок канал зарекомендовал себя как надежный партнер для рекламы в TG. Размещайте интеграции уже сегодня и привлекайте новых клиентов вместе с Telega.in!
Вы снова сможете добавить каналы в корзину из каталога
Комментарий