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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download 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"
Что такое try-with-resources? 🤓

Ответ:

try-with-resources (Java 7+) автоматически закрывает ресурсы, реализующие интерфейс AutoCloseable (например, FileInputStream). Это упрощает управление ресурсами, предотвращая утечки.

Пример:

try (FileInputStream fis = new FileInputStream("file.txt")) {

// Работа с файлом
} catch (IOException e) {
e.printStackTrace();
}

Ресурсы закрываются автоматически после выхода из блока try.

#собеседование
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 — var

Ключевое слово var, добавленное в Java 10, представляет собой локальную типизированную переменную с выводом типа (local variable type inference). Хотя var сам по себе не является типом (в отличие от String, List, и т.п.), он оперирует ссылочными (и примитивными) типами — именно поэтому мы рассматриваем его как часть экосистемы ссылочных типов.

var позволяет сократить синтаксис, делая код лаконичнее, при этом тип переменной всё равно строго определяется на этапе компиляции.

Синтаксис и пример использования

var list = new ArrayList<String>();
var name = "John";
var age = 25;


Это полностью эквивалентно:
ArrayList<String> list = new ArrayList<>();
String name = "John";
int age = 25;


Тип переменной вычисляется во время компиляции, и далее не может быть изменён. var нельзя использовать без инициализации:
var name; // ошибка компиляции


Что происходит на уровне компиляции и памяти

На уровне байткода и JVM var не существует — это просто синтаксический сахар. Компилятор javac анализирует выражение справа от знака =, определяет точный тип и подставляет его вместо var.

Пример:
var user = new User("Alice");


Компилируется в:
User user = new User("Alice");


На уровне памяти всё ведёт себя так же, как если бы вы явно указали тип: объект User создаётся в куче (heap), а ссылка user — в стеке (если переменная локальная). То есть var никак не влияет на runtime-поведение, управление памятью или структуру объектов.

Где можно использовать var

Только внутри методов (локальные переменные)
В циклах for-each
В try-with-resources


Примеры:
for (var entry : map.entrySet()) {
...
}

try (var stream = Files.lines(path)) {
...
}


Нельзя использовать:
Для параметров методов
Для полей классов
В сигнатурах методов


Преимущества использования var

1. Ускорение читаемости

Map<String, List<User>> usersByRole = new HashMap<>();


var usersByRole = new HashMap<String, List<User>>();


Меньше дублирования, особенно при использовании дженериков.

2. Быстрая прототипизация


При тестировании и прототипах позволяет писать код быстрее.

3. Минимизация шаблонного кода

Особенно полезно в циклах:
for (var entry : map.entrySet()) { ... }


Недостатки и подводные камни

1. Потеря явности

var может скрыть реальный тип переменной, что ухудшает читаемость, особенно в больших проектах или при чтении чужого кода:
var x = process(); // Что возвращает process()? Map? List? String?


2. Не подходит для API и контрактов

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

3. Опасности с null

Пример:
var data = null; // ошибка компиляции: невозможно вывести тип


Тип должен быть определён по выражению. null без контекста не имеет типа.


4. Может скрыть ошибки


В случае приведения типов или неочевидных фабрик:
var list = Arrays.asList(1, 2, 3); // list: List<Integer>, но неизменяемый!


Программист может подумать, что это ArrayList.

5. Не подходит для примитивов, если важна производительность
var x = 42; // int
var y = 42L; // long

// Может быть неожиданным, если x и y пойдут в разные ветви перегрузки


Лучшие практики использования var

Использовать var, когда тип очевиден из правой части.
Не использовать в публичных API и библиотечном коде.
Избегать var, если тип сложный или поведение неочевидно.
Можно комбинировать с IDE: использовать var в коде, но просматривать тип через наведение мыши.


Пример хорошего использования:
var list = new ArrayList<String>(); // тип легко читается


Пример плохого использования:
var result = service.process(); // неясно, что такое result


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

import java.util.function.Function;

public class Task190625 {
public static void main(String[] args) {
var x = (Function<Function<Integer, Integer>, Integer>)
f -> f.apply(10);

var y = x.apply(n -> n * 2);
System.out.println(y);
}
}


#Tasks
StreamAPI JAVA.
Великолепие минимализма

Видео посвященное изучению Stream API в Java.

Что мы узнали:
Что такое Stream API и зачем оно вообще нужно.
Что такое Императивный и Декларативный подходы.
Рассмотрели функциональные интерфейсы и их основные виды.
Рассмотрели основные функциональные промежуточные и терминальные методы.
Посмотрели все это на примерах.

Если хотите посмотреть с более подробными примерами и описанием:
GitHub -
https://github.com/Oleborn/StreamAPI_Research
(понравилось - поставь звездочку)


Ссылка на Youtube
Ссылка на Рутьюб

Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
Что такое Error в Java и чем он отличается от Exception? 🤓

Ответ:

Error и Exception — наследники Throwable.

Error обозначает серьезные системные ошибки, которые обычно нельзя обработать (например, OutOfMemoryError).

Exception — это ошибки, которые можно и нужно обрабатывать (например, IOException).

Программист редко обрабатывает Error, но должен учитывать Exception.

#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM