Java Portal | Программирование
13K subscribers
1.19K photos
98 videos
37 files
1.12K links
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика

Связь: @devmangx

РКН: https://clck.ru/3H4WUg
Download Telegram
Spring Boot Istio 1.2.0 вышел

Что подтянули в обновлении:

🍃авто-генерация fault-ов
🍃 авто-создание и инжект gateway
🍃 авто-генерация HTTP matches

Детали тут : https://github.com/piomin/spring-boot-istio

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
Принцип открытости/закрытости (OCP): это принцип из SOLID, который говорит, что классы должны быть открыты для расширения, но закрыты для модификации.

Вместо правки существующей реализации стоит добавлять новое поведение через интерфейсы и наследование в Java, не трогая уже написанный код.

// Плохой способ реализовать генератор отчётов
class ReportGenerator {
public void generateReport(String type) {
if (type.equals("PDF")) {
System.out.println("Generating PDF Report...");
} else if (type.equals("CSV")) {
System.out.println("Generating CSV Report...");
} else if (type.equals("EXCEL")) {
System.out.println("Generating Excel Report...");
}
}
}

// Более правильный вариант

// Определяем интерфейс
interface Report {
void generate();
}

// Реализации
class PdfReport implements Report {
public void generate() {
System.out.println("Generating PDF Report...");
}
}

class CsvReport implements Report {
public void generate() {
System.out.println("Generating CSV Report...");
}
}

// Используем конкретную реализацию
public class ReportApp {
public static void main(String[] args) {
Report report = new PdfReport();
report.generate();
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍83🤔2
У платформенных потоков в Java есть 6 состояний. У виртуальных потоков их около 20, но они скрыты от нас.

Держите свежий выпуск, где автор показывает, как с помощью глубокой рефлексии можно разобраться, как это вообще устроено:

Узнаем здесь! 🤭

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Java-совет : избегай преждевременной оптимизации.

Сначала сосредоточься на чистом, рабочем коде.

Пиши код, который корректно работает, и в первую очередь закрывает функциональные требования.

// Простейший пример
String helloThere = "Hello " + "there" + "!";
System.out.println(helloThere);

// Эта строка кода читаемая и работает как задумано

// Позже можно подумать об оптимизации через StringBuilder
StringBuilder sb = new StringBuilder();
sb.append("Hello ");
sb.append("there");
sb.append("!");
System.out.println(sb.toString());


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🤔42
Arconia для Spring Boot Dev Services и Observability

В этом посте объясняется, как использовать фреймворк Arconia для улучшения опыта разработки со Spring Boot. Проект совсем свежий и активно развивается. Меня он зацепил одной фичей, которую я люблю в Quarkus, но которой не хватает в Spring Boot. Речь про Dev Services. Если вы работали с Quarkus, то наверняка знаете, о чём речь. Dev Services позволяют автоматически поднимать не сконфигуренные сервисы в dev-режиме и при тестировании. Как и в Quarkus, Arconia базируется на Testcontainers и использует поддержку Spring Boot Testcontainers.

Чтобы разобраться, как Spring Boot работает с Testcontainers, посмотрите статью на эту тему. Если интересуют Dev Services в Quarkus, то вот пост, который фокусируется на автоматизации тестирования в Quarkus.

Можете использовать этот исходный код, если хотите попробовать. Для этого просто склонируйте пример из GitHub и следуйте инструкциям.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
Spring Boot: чтобы сервисы возвращали пагинированный ответ, а не огромный список, можно использовать Page<T> и Pageable.

Без пагинации:

[
{ "id": 1, "name": "John" },
{ "id": 2, "name": "Lia" }
...
]


С пагинацией:

{
"content": [
{ "id": 1, "name": "John" },
{ "id": 2, "name": "Lia" }
...
],
"page": {
"size": 20,
"number": 0,
"totalElements": 50213,
"totalPages": 2511
}
}


Вместо того чтобы напрямую возвращать Page<T>, можно вернуть кастомный paged response DTO, чтобы не светить типы фреймворка в API.

record PagedResponse<T>(
List<T> items,
int page,
int size,
long totalElements,
int totalPages
) {}


И метод контроллера будет выглядеть примерно так:

@GetMapping
public PagedResponse<User> getUsers(Pageable pageable) {
Page<User> page = repository.findAll(pageable);

return new PagedResponse<>(
page.getContent(),
page.getNumber(),
page.getSize(),
page.getTotalElements(),
page.getTotalPages()
);
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
Паттерны архитектуры приложений Spring Boot: здесь

Серебряной пули не существует. Когда речь заходит об архитектуре современного приложения, часто можно услышать, что Anemic Domain Model — это плохо, или что Transaction Script — это антипаттерн. Также многие советуют Clean Architecture или Hexagonal Architecture в связке с DDD как «лучшую» или «правильную» архитектуру.

Но бесплатных обедов не бывает. Любое решение всегда приходит со своим набором компромиссов. Важно понимать эти trade-offы и выбирать архитектуру, которая лучше всего подходит под конкретные требования приложения.

Если вы делаете микросервис для одного конкретного сабдомена, возможно, простой слоистой архитектуры будет вполне достаточно. Если это монолит с низкой или средней сложностью — модульный монолит может быть хорошим выбором. Но если вы строите сложную систему с высокой сложностью, несколькими сабдоменами, процессами и воркфлоу, тогда имеет смысл задуматься о модульном монолите с DDD и гексагональной архитектурой.

Может возникнуть вопрос: почему стоит довольствоваться «достаточно хорошей» архитектурой, а не сразу делать «лучшую»?

Ответ простой: всё упирается в соотношение стоимости и пользы. Архитектура «достаточно хорошего уровня» в большинстве случаев полностью закрывает потребности приложения и при этом её проще реализовывать, поддерживать и развивать, чем идеальную, но переусложнённую архитектуру.

Лично я считаю, что исправлять недоинженеренную систему проще, чем переинженеренную. Добавлять всегда легче, чем убирать.

Представьте, что вы работаете с большим существующим кодбейсом и на 99% уверены, что одна из библиотек нигде не используется. Но удалить её страшно — вдруг что-то сломается. С архитектурой та же история. Если вы однажды переусложнили решение, потом очень трудно это откатить или упростить.

Поэтому лучше начинать с архитектуры «достаточно хорошего уровня» и эволюционировать её по мере развития системы.

Именно это и демонстрируется в данном репозитории: реализация примера приложения с использованием разных архитектурных подходов. Начиная с простой слоистой архитектуры и постепенно переходя к модульному монолиту с DDD и гексагональной архитектурой. В каждом модуле дизайн и архитектура улучшаются за счёт применения лучших практик и паттернов.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
Совет по Java: предпочитай инъекцию через конструктор, а не инъекцию в поля.

Инъекция в поле:

@Component
public class UserController {

@Autowired
private Logger logger;

public void createUser(String username) {
...
}
}

// Сложнее тестировать изолированно.

Инъекция через конструктор:

...
private final Logger logger;

@Autowired
public UserController(Logger logger) {
this.logger = logger;
}

...
// Проще создавать экземпляр для unit-тестов


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Топ оконных функций, которые использует каждый data-инженер

1. ROW_NUMBER()
ROW_NUMBER() позволяет пронумеровать строки в рамках группы, что сильно упрощает дедупликацию. Нужно взять последнюю запись по клиенту или первое событие в сессии — решается чисто и без костылей.

2. DENSE_RANK()
Если делаешь лидерборды или бизнес-уровни, эта функция всплывает почти сразу. Она группирует одинаковые значения без пропусков в нумерации — рейтинги получаются понятными даже для нетехнических стейкхолдеров.

3. LAG() / LEAD()
Используются, чтобы посмотреть на предыдущее или следующее значение. Идеально подходит для сравнения сегодняшних продаж со вчерашними или поиска изменений между событиями.

4. SUM() OVER()
Так делаются накопительные суммы без развала запроса. SUM() OVER() позволяет сохранить детализацию по строкам и при этом добавить кумулятивные итоги. Очень удобно в финансовых и событийных пайплайнах.

5. FIRST_VALUE() / LAST_VALUE()
Нужны, когда важен контекст. Помогают взять первое или последнее значение внутри партиции — критично для временной аналитики, например при сравнении стартовых и финальных значений или расчёте метрик жизненного цикла.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2😁2
Spring Boot: если в коде используется RestTemplate, тесты можно писать, подменяя внешние HTTP-вызовы с помощью MockRestServiceServer.

MockRestServiceServer работает за счет перехвата HTTP-запросов.

Дан сервис, который дергает внешний API:

@Service
public class ProductService {

private final RestTemplate restTemplate;

public ProductService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public String getProductName(long id) {
Product product = restTemplate.getForObject(
"https://remoteapi.com/products/{id}",
Product.class,
id
);
return product.getName();
}
}



Тест можно реализовать так:

@SpringBootTest
class ProductServiceTest {

@Autowired
private RestTemplate restTemplate;

@Autowired
private ProductService productService;

private MockRestServiceServer mockServer;

@BeforeEach
void setup() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}

@Test
void shouldReturnProductWhenExternalApiCalled() {
// Arrange
mockServer.expect(requestTo("https://remoteapi.com/products/1"))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(
"{\"id\":1,\"name\":\"USB stick\"}",
MediaType.APPLICATION_JSON
));

// Act
ProductDto product = productService.getProduct(1L);

// Assert
assertThat(product.getName()).isEqualTo("USB stick");

mockServer.verify();
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍54🔥2😁2
Нашли офигенный способ выучить PostgreSQL в браузере : crunchydata

PostgreSQL-песочница с практическими уроками SQL, транзакциям, индексам, PostGIS и не только

🛌

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍122😁1
Java: не пихай бизнес-логику в Stream.peek(). Используй его только для отладки.

Смысл простой: peek() предназначен для легкого дебага и просмотра потока, а не для вычислений или побочных эффектов.

Используй только для легкой отладки

Пример: просмотр (инспекция) потока пайплайна

list.stream()
.filter(x -> x > 10)
.peek(x -> System.out.println("Filter: " + x))
.map(x -> x * 2)
.peek(x -> System.out.println("Map: " + x))
.toList();


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94
📱 Держите 6 хороших каналов по искусственному интеллекту и программированию для любого уровня!

Выбирай направление:

📱 Нейросети@neuro_prompt

🤖 AI-инструменты @ai_prompt

📱 Python@python_prompt

🤔 InfoSec & Хакинг @infosec_prompt

👩‍💻 IT Новости @it_news

😄 IT Мемы@it_memes

Промпты, обучение, шпаргалки и полезные ресурсы на каждую тему!
Please open Telegram to view this post
VIEW IN TELEGRAM
🌚2🔥1
Под капотом многопоточной синхронизации в Java: как потоки договариваются через Mark Word

Синхронизация в Java часто воспринимается как простая языковая конструкция — достаточно использовать ключевое слово synchronized, и код начинает «просто работать».

На практике же на уровне JVM происходит цепочка событий, которую можно проследить до Mark Word — восьмибайтового служебного поля заголовка каждого Java-объекта.

Современные JVM (HotSpot, OpenJ9, GraalVM) не используют фиксированную модель блокировок. Вместо этого они динамически выбирают стратегию синхронизации, исходя из реального поведения потоков и истории использования объекта.

Эта статья предназначена для Java‑разработчиков, которые уже знакомы с многопоточностью и synchronized, но хотят разобраться, как именно JVM управляет блокировками, какие состояния проходит объект и какую роль в этом играет Mark Word.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Java подсказка : не злоупотребляй наследованием. Когда можно — лучше делегируй. Наследование создаёт сильную связку, и это может выстрелить в ногу, если базовый класс изменится.

Предположим, у нас есть такой класс:

class Engine {
void start() {
}
}


и Car наследуется от Engine:

class Car extends Engine {
void drive() {
start();
}
}


Наследование выражает отношение is, но автомобиль на самом деле не является двигателем, он имеет двигатель. Перепишем через делегацию:

class Car {
private Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void drive() {
engine.start();
}
}


Таким образом эти два класса развязаны, и отношение превращается в has.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
А может ли Java гонять TensorFlow без JNI и без Python?

Автор взял Java 25 + FFM и протащил это всё до C-шного TensorFlow API, собрав рабочий REST-сервис на macOS.

Результат: предсказуемая память, нативная производительность и максимально скучная (в хорошем смысле) архитектура.

Ломали когда-нибудь Quarkus-эндпоинт просто тем, что решили залогировать request body?

В этом гайде показывают, как безопасно аудировать, чистить и трассировать HTTP-запросы через request filters в Quarkus, не блокируя обработку и не убивая API.

Практично и можно почти копипастить.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👀3
Java: не вешай логику в Stream.peek(), используй его только для отладки.

Используй его для легкой отладки

Пример: инспекция потока пайплайна

list.stream()
.filter(x -> x > 10)
.peek(x -> System.out.println("Filter: " + x))
.map(x -> x * 2)
.peek(x -> System.out.println("Map: " + x))
.toList();



👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔3
СХЕМЫ АУТЕНТИФИКАЦИИ

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍6🤔2🤣1
Spring Boot. Чтобы Jackson создавал объекты из JSON явно и предсказуемо, можно использовать аннотацию
@JsonCreator

Каждый параметр явно биндится.

Определяем конструктор с @JsonCreator:

class User {
public final String username;
public final int age;

@JsonCreator
public User(
@JsonProperty("username") String username,
@JsonProperty("age") int age
) {
this.username = username;
this.age = age;
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
11
Многопоточность позволяет писать так, чтобы несколько задач выполнялись параллельно внутри одного приложения.

Чтобы использовать многопоточность (то есть писать многопоточный код), нужен класс java.lang.Thread.

Стадии жизненного цикла потока:

• New: Новый поток начинает жизнь в состоянии new. Он остается там, пока программа не запустит поток.

• Runnable: После запуска новый поток становится runnable. В этом состоянии считается, что поток выполняет свою работу.

• Waiting: Иногда поток переходит в waiting, когда ему нужно дождаться выполнения задачи другим потоком.

• Timed Waiting: Поток из runnable может перейти в timed waiting на определенный промежуток времени. После истечения этого времени он снова возвращается в runnable.

• Terminated: Поток попадает в terminated после завершения задачи или принудительного завершения.

Приоритеты потоков:

Каждый Java-поток имеет приоритет, который помогает ОС решать порядок планирования потоков.

• MIN_PRIORITY (константа 1)
• NORM_PRIORITY (константа 5) (приоритет по умолчанию)
• MAX_PRIORITY (константа 10)

Базовые способы создать поток в Java:

• Реализовать интерфейс Runnable
• Наследоваться от Thread

Методы потоков:

• public void start()
Запускает поток в отдельном пути выполнения и затем вызывает run() у этого объекта Thread.

• public void run()
Если объект Thread был создан с отдельным Runnable, то run() будет вызван на этом Runnable.

• public final void setPriority(int priority)
Устанавливает приоритет потока. Возможные значения от 1 до 10.

• public void interrupt()
Прерывает поток, заставляя продолжить выполнение, даже если он был заблокирован.

• public final boolean isAlive()
Возвращает true, если поток "жив", то есть после старта и до завершения.

Это были базовые вещи. Пост длинный, но надеюсь, что что-то новое унес с собой.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92
Spring Boot. С помощью @DataJpaTest можно прогонять JPA репозитории изолированно.

@DataJpaTest поднимает только JPA слой без всего приложения, использует in-memory базу H2 и откатывает транзакции после каждого теста.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
6