Java for Beginner
675 subscribers
547 photos
155 videos
12 files
839 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Выбираем темы для рассмотрения в следующие выходные! 🤨
Anonymous Poll
32%
Optional
24%
AOP
29%
JSON
15%
IO/NIO
Встреча создана!

https://telemost.yandex.ru/j/55299189134160

залетаем! ✈️
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Типы миграций и версионирование в Flyway

1. Структура SQL-миграций

Flyway классифицирует SQL-миграции по префиксам в именах файлов, определяя их поведение при выполнении.

1.1. Именование файлов

Версионные миграции (Versioned)

Префикс V + версия + описание:
V<Версия>__<Описание>.sql


Пример:
-- V1__Create_users_table.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL
);


Повторяемые миграции (Repeatable)

Префикс R + описание:
R__<Описание>.sql


Пример:
-- R__Update_user_view.sql
CREATE OR REPLACE VIEW user_view AS
SELECT id, username FROM users;


2. Java-миграции

Позволяют описывать миграции на Java для сложной логики, недоступной в SQL.

2.1. Реализация интерфейсов


JdbcMigration (устаревший):
public class V2__InsertTestData implements JdbcMigration {
@Override
public void migrate(Connection connection) throws Exception {
try (Statement stmt = connection.createStatement()) {
stmt.execute("INSERT INTO users (username) VALUES ('admin')");
}
}
}


JavaMigration (рекомендуемый):
public class V3__AddAdminUser implements JavaMigration {
@Override
public void migrate(Context context) throws Exception {
try (Statement stmt = context.getConnection().createStatement()) {
stmt.execute("INSERT INTO users (username) VALUES ('superuser')");
}
}
}


2.2. Правила

Классы должны находиться в classpath (обычно src/main/java/db/migration).
Имя класса соответствует имени файла SQL-миграции (например, V2__InsertTestData.java).

3. Правила версионирования

3.1. Семантическое версионирование

Рекомендуемый формат версии:
V<Мажор>.<Минор>.<Патч>__<Описание>.sql


Пример:
-- V1.2.3__Fix_email_constraint.sql
ALTER TABLE users ALTER COLUMN email SET NOT NULL;


Преимущества:
Понятная история изменений.
Совместимость с Semantic Versioning.


3.2. Откат изменений

Flyway не поддерживает автоматический откат. Альтернативы:

Новая миграция для отмены изменений:
-- V3__Drop_users_table.sql
DROP TABLE users;


Callbacks (SQL-хуки):
Скрипты beforeMigrate/afterMigrate для резервного копирования.

Важно: Не изменяйте уже примененные миграции — это нарушит целостность flyway_schema_history.

4. Примеры

4.1. SQL-миграции
-- V1__Initial_schema.sql
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100)
);

-- R__Update_view.sql
CREATE OR REPLACE VIEW active_users AS
SELECT * FROM users WHERE deleted_at IS NULL;


4.2. Java-миграция

public class V4__EncryptPasswords implements JavaMigration {
@Override
public void migrate(Context context) throws Exception {
try (PreparedStatement ps = context.getConnection()
.prepareStatement("UPDATE users SET password = encrypt(password)")) {
ps.executeUpdate();
}
}
}


#Java #middle #Flyway
Что выведет код?

import java.util.stream.IntStream;

public class Task160625 {
public static void main(String[] args) {
IntStream.rangeClosed(1, 5)
.filter(i -> i % 2 == 0)
.peek(System.out::print)
.forEachOrdered(i -> {});
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
12%
Ничего не выведет
12%
12345
12%
135
65%
24
Чем отличается ConcurrentHashMap от HashMap? 🤓

Ответ:

ConcurrentHashMap — потокобезопасная версия HashMap, предназначенная для многопоточных приложений.

Она использует сегментированную блокировку (lock striping), чтобы минимизировать конфликты. HashMap не потокобезопасна, и одновременный доступ из нескольких потоков может привести к ошибкам.

Пример:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1); // Потокобезопасно

ConcurrentHashMap не блокирует всю структуру, а только отдельные сегменты.

#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Ссылочные типы в Java — интерфейсы (interfaces)

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

Понимание интерфейсов необходимо для эффективного взаимодействия с фреймворками, библиотеками и построения легко расширяемого кода.

Создание интерфейсов

Интерфейсы объявляются с помощью ключевого слова interface. Они содержат объявления методов без реализации (до Java 8) или с ограниченной реализацией (начиная с Java 8):

public interface Animal {
void makeSound();
}


Класс, реализующий интерфейс, должен предоставить реализацию всех его методов:
public class Dog implements Animal {
public void makeSound() {
System.out.println("Woof");
}
}


Начиная с Java 8, интерфейсы могут содержать:
default-методы с реализацией
static-методы
private-методы (с Java 9)


public interface Logger {
default void log(String msg) {
System.out.println("Log: " + msg);
}
}


Ключевые особенности:
Интерфейс не может содержать поля с реализацией — только public static final константы.
Все методы по умолчанию public abstract, если не указано иное.
Интерфейс — это тип, и его можно использовать как ссылку.


Использование интерфейсов

Интерфейсы позволяют описывать поведение без привязки к конкретной реализации:
public void processAnimal(Animal animal) {
animal.makeSound(); // работает с любым классом, реализующим Animal
}


Это даёт возможность:
использовать полиморфизм,
отделять абстракции от реализаций,
писать гибкий и расширяемый код.

Интерфейсы можно использовать как:
параметры методов
типы переменных
результаты возвращаемых значений
обобщенные типы


Также интерфейсы — неотъемлемая часть функционального программирования в Java 8+:
@FunctionalInterface
public interface Converter<F, T> {
T convert(F from);
}



Существование и удаление

Поскольку интерфейсы — это ссылочные типы, они работают как любые другие объекты. Переменная типа интерфейса — это ссылка на объект, реализующий этот интерфейс.
Animal animal = new Dog();


Здесь animal — это ссылка на объект типа Dog, но доступ к нему осуществляется через интерфейс Animal. Удаление объекта происходит по общим правилам: когда все ссылки исчезают, он становится доступным для сборки мусора.


Полиморфизм через интерфейсы

Интерфейсы — один из основных инструментов реализации полиморфизма. Код, написанный против интерфейсов, легко расширяем:
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
Здесь List и Map — интерфейсы, а ArrayList и HashMap — конкретные реализации. Это позволяет заменить реализацию без изменения остального кода.


#Java #для_новичков #beginner #reference_types #Interface
Множественное наследование

Классы в Java не могут наследовать более одного класса, но могут реализовать несколько интерфейсов:
public interface Flyable {
void fly();
}

public interface Swimmable {
void swim();
}

public class Duck implements Flyable, Swimmable {
public void fly() { ... }
public void swim() { ... }
}
Это решает проблему ограничений одиночного наследования и позволяет композировать поведение.



Трудности и подводные камни

1. Конфликт default-методов

Если класс реализует несколько интерфейсов, в которых есть default-методы с одинаковыми сигнатурами, возникает конфликт:

interface A {
default void show() { System.out.println("A"); }
}
interface B {
default void show() { System.out.println("B"); }
}
class C implements A, B {
public void show() {
A.super.show(); // Явное разрешение конфликта
}
}


2. Отсутствие состояния
Интерфейсы не могут содержать нестатические поля, что ограничивает их в сравнении с абстрактными классами. Всё, что можно объявить — это public static final константы.

3. Непредсказуемое поведение equals/hashCode

Если объект используется через интерфейс, его поведение equals() и hashCode() может зависеть от реализации, что важно при использовании в коллекциях.

4. Ошибки при переопределении
Ошибки в сигнатурах при реализации интерфейса не всегда очевидны. Например, случайное переопределение метода с другой сигнатурой может вызвать баг.

5. Подмена реализации
Использование интерфейса как типа может скрывать специфичное поведение конкретной реализации:

List<String> list = new LinkedList<>();
list.get(0); // Поведение может отличаться от ArrayList



Дополнительные нюансы

1. Функциональные интерфейсы
С Java 8 появились интерфейсы с единственным абстрактным методом — функциональные интерфейсы. Они могут быть использованы с лямбда-выражениями:
Runnable r = () -> System.out.println("Run");


2. Интерфейсы и обобщения
Интерфейсы часто комбинируются с generics для повышения универсальности:
public interface Repository<T> {
void save(T entity);
}


3. Marker-интерфейсы
Некоторые интерфейсы, такие как Serializable или Cloneable, не содержат методов. Они используются как маркеры для определения поведения JVM или библиотек.

4. Интерфейсы и наследование
Интерфейс может наследовать другие интерфейсы:
interface A { void a(); }
interface B extends A { void b(); }
Класс, реализующий B, обязан реализовать методы a() и b().


5. Интерфейсы и динамические прокси
Через интерфейсы создаются динамические прокси, например, в java.lang.reflect.Proxy, что активно используется в Spring, Hibernate и других фреймворках.

#Java #для_новичков #beginner #reference_types #Interface
Что выведет код?

interface A170625 {
default void show() {
System.out.println("A");
}
}

interface B170625 extends A170625 {
default void show() {
System.out.println("B");
}
}

interface C170625 extends A170625 {}

class D170625 implements B170625, C170625 {
public static void main(String[] args) {
new D170625().show();
}
}


#Tasks
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
Чем отличается Iterator от ListIterator? 🤓

Ответ:

Iterator позволяет перебирать элементы коллекции в одном направлении и удалять их (remove()).

ListIterator расширяет Iterator для списков (List), добавляя возможность двунаправленного перебора (previous(), hasPrevious()) и модификации элементов (set()).

Пример:

List<String> list = new ArrayList<>(Arrays.asList("A", "B"));
ListIterator<String> it = list.listIterator();
it.next(); // Переход к "A"
it.set("C"); // Замена "A" на "C"

#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Интеграция Flyway с инструментами

1. Maven: плагин flyway-maven-plugin
Настройка в pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>9.22.0</version>
<configuration>
<url>jdbc:postgresql://localhost:5432/mydb</url>
<user>postgres</user>
<password>password</password>
<locations>
<location>classpath:db/migration</location>
</locations>
</configuration>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>


Ключевые параметры:

url — JDBC-строка подключения.
locations — пути к папкам с миграциями (classpath: или filesystem:).
baselineVersion — версия для инициализации существующей БД (если не пустая).


Команды:
mvn flyway:migrate  # Применить миграции
mvn flyway:info # Показать статус
mvn flyway:clean # Очистить БД (удалить все объекты)


2. Gradle: плагин org.flywaydb.flyway
Настройка в build.gradle:
plugins {
id "org.flywaydb.flyway" version "9.22.0"
}

flyway {
url = 'jdbc:postgresql://localhost:5432/mydb'
user = 'postgres'
password = 'password'
locations = ['classpath:db/migration']
}

dependencies {
flywayRuntime 'org.postgresql:postgresql:42.6.0'
}


Команды:
gradle flywayMigrate  # Применить миграции
gradle flywayInfo # Показать статус


3. Интеграция с Spring Boot
Автоконфигурация через application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: postgres
password: password
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true # Игнорировать существующую БД
validate-on-migrate: false # Отключить валидацию (для dev)


Принцип работы:

При старте приложения Spring Boot автоматически:
Проверяет наличие таблицы flyway_schema_history.
Применяет невыполненные миграции из указанных в locations.
Если baseline-on-migrate: true, Flyway инициализирует БД без ошибок, даже если она не пуста.


Важные свойства:
spring.flyway.clean-disabled — запрет на случайную очистку БД (по умолчанию true в prod).
spring.flyway.table — кастомное имя для таблицы истории (по умолчанию flyway_schema_history).


4. Callbacks (SQL-хуки)

SQL-скрипты, выполняемые до/после основных операций Flyway (миграции, очистки и т.д.).

Поддерживаемые события:
beforeMigrate, afterMigrate
beforeClean, afterClean
beforeInfo, afterInfo


Пример использования:


Создайте файл db/migration/beforeMigrate.sql:
-- beforeMigrate.sql
CREATE TABLE IF NOT EXISTS _flyway_audit (
operation VARCHAR(20),
timestamp TIMESTAMP
);
INSERT INTO _flyway_audit VALUES ('migration_started', NOW());


Flyway выполнит этот скрипт перед применением миграций.

Правила:
Имена файлов должны соответствовать шаблону: <event>.sql (например, afterMigrate.sql).
Размещаются в папке locations (рядом с миграциями).


5. Мультимодульные проекты (Maven/Gradle)

Если миграции находятся в отдельном модуле:
Укажите путь к ресурсам через filesystem::
<!-- Maven -->
<location>filesystem:${project.basedir}/../migrations/src/main/resources/db/migration</location>


// Gradle
locations = ['filesystem:../migrations/src/main/resources/db/migration']


6. Пропуск миграций в тестах

В application-test.yml:
spring:
flyway:
enabled: false


7. Кастомные места хранения миграций

S3-хранилище (через Flyway Teams):
spring:
flyway:
locations: s3://my-bucket/db/migration


Классовый путь + файловая система:
locations: classpath:db/migration, filesystem:/opt/migrations


#Java #middle #Flyway
Что выведет код?

import java.util.Optional;

public class Task180625 {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable(null)
.flatMap(s -> Optional.of("value"))
.or(() -> Optional.of("default"));

System.out.println(opt.get());
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
20%
NoSuchElementException
25%
null
30%
"default"
25%
"value"