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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Конструктор и как его получить

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

Пример простого конструктора:
public class Person {
private String name;
private int age;

// Конструктор
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}


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


Для работы с конструкторами используется класс java.lang.reflect.Constructor. Мы можем получить все конструкторы класса или конкретный конструктор с определенными параметрами.

Методы для получения конструкторов

getConstructors()
Этот метод возвращает массив всех публичных конструкторов класса. Конструкторы, объявленные с модификатором доступа private, protected или без модификатора (package-private), не будут включены в результат.

Пример:
import java.lang.reflect.Constructor;

public class Main {
public static void main(String[] args) {
try {
// Получаем класс Person
Class<?> personClass = Class.forName("Person");

// Получаем все публичные конструкторы
Constructor<?>[] publicConstructors = personClass.getConstructors();

// Выводим информацию о конструкторах
for (Constructor<?> constructor : publicConstructors) {
System.out.println("Constructor: " + constructor);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}


Вывод:
Constructor: public Person(java.lang.String,int)


Плюсы:
Простота использования.
Возвращает только публичные конструкторы, что может быть полезно для безопасности.


Минусы:
Не возвращает приватные или защищенные конструкторы.

getDeclaredConstructors()
Этот метод возвращает массив всех конструкторов класса, включая приватные, защищенные и package-private. В отличие от getConstructors(), этот метод позволяет получить доступ ко всем конструкторам, независимо от их модификатора доступа.

Пример:
import java.lang.reflect.Constructor;

public class Main {
public static void main(String[] args) {
try {
// Получаем класс Person
Class<?> personClass = Class.forName("Person");

// Получаем все конструкторы (включая приватные)
Constructor<?>[] allConstructors = personClass.getDeclaredConstructors();

// Выводим информацию о конструкторах
for (Constructor<?> constructor : allConstructors) {
System.out.println("Constructor: " + constructor);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}


Вывод:
Constructor: public Person(java.lang.String,int)
Constructor: private Person()


Плюсы:
Возвращает все конструкторы, включая приватные.
Полезен для глубокого анализа класса.


Минусы:
Может потребовать дополнительных действий для работы с приватными конструкторами (например, вызов setAccessible(true)).

Нюансы использования
Доступ к приватным конструкторам: Если вы хотите использовать приватный конструктор, вам нужно вызвать метод setAccessible(true) на объекте Constructor, чтобы обойти проверку доступа.
Безопасность: Использование рефлексии может нарушить инкапсуляцию, поэтому будьте осторожны при работе с приватными конструкторами.

#Java #Training #Medium #Reflection_API #Constructor
👍1
Что выведет код?

public class Task100225 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
if (i == 6) {
continue;
}
System.out.print(i + " ");
}
}
}


#Tasks
👍1
Варианты ответа:
Anonymous Quiz
5%
0 1 2
78%
0 1 2 3 4
7%
StackOverflow
10%
RuntimeException
👍1
Когда используешь незнакомые плагины 🤪 😁

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Вопросы с собеседования 👩‍💻

Какой модификатор доступа делает метод доступным только внутри пакета?
Anonymous Quiz
11%
public
23%
private
35%
default
32%
protected
👍2🔥1
Работа с параметрами конструкторов

Когда мы получаем конструктор с помощью рефлексии, часто нужно узнать, какие параметры он принимает. Для этого используется метод getParameterTypes(), который возвращает массив объектов Class<?>, представляющих типы параметров конструктора.

Пример:
import java.lang.reflect.Constructor;

public class Main {
public static void main(String[] args) {
try {
// Получаем класс Person
Class<?> personClass = Class.forName("Person");

// Получаем все конструкторы
Constructor<?>[] constructors = personClass.getDeclaredConstructors();

// Анализируем параметры каждого конструктора
for (Constructor<?> constructor : constructors) {
System.out.println("Constructor: " + constructor);

// Получаем типы параметров
Class<?>[] parameterTypes = constructor.getParameterTypes();
System.out.println("Parameter types:");
for (Class<?> paramType : parameterTypes) {
System.out.println(" - " + paramType.getName());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}


Вывод:

Constructor: public Person(java.lang.String,int)
Parameter types:
- java.lang.String
- int

Constructor: private Person()
Parameter types:


Как использовать конструктор с параметрами

После получения конструктора и информации о его параметрах, мы можем создать новый экземпляр класса с помощью метода newInstance(). Если конструктор принимает параметры, их нужно передать в newInstance().

Пример:
import java.lang.reflect.Constructor;

public class Main {
public static void main(String[] args) {
try {
// Получаем класс Person
Class<?> personClass = Class.forName("Person");

// Получаем конструктор с параметрами (String, int)
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);

// Создаем экземпляр класса с параметрами
Object personInstance = constructor.newInstance("John", 30);

// Выводим результат
System.out.println("Person created: " + personInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}


Вывод:

Person created: Person@<hashcode>


Плюсы и минусы работы с параметрами конструкторов

Плюсы:
Гибкость: можно создавать объекты с разными параметрами во время выполнения.
Возможность анализа и использования конструкторов, которые не известны на этапе компиляции.


Минусы:
Сложность: работа с рефлексией требует больше кода и внимания к деталям.
Ошибки времени выполнения: если передать неправильные параметры, возникнет исключение.


Нюансы использования

Проверка типов: Убедитесь, что типы параметров, передаваемых в newInstance(), соответствуют ожидаемым типам конструктора.
Обработка исключений: Метод newInstance() может выбрасывать исключения, такие как InstantiationException, IllegalAccessException, IllegalArgumentException и InvocationTargetException. Их нужно обрабатывать.


#Java #Training #Medium #Reflection_API #Constructor
👍1
Не могу не опубликовать.

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

Это явно показывающий пример того, что такое программирование на самом деле. Всему, что описал этот человек Вас не научат на курсах Мишустина, OTUS, и бог знает каких еще...🤦‍♂️
Все это - собранный по крупицам многолетний опыт, который мне, да и большинству из нас еще предстоит заработать.

Но и относиться к этому как к ИСТИНЕ принесенной мессией, тоже не стоит. Уверен, что в среде опытных разработчиков, нашли бы что возразить на некоторые доводы, опять же потому - что все это плоды опыта)))


В целом, я благодарен за критику. Я знаю, что пишу как новичок, каким по сути и являюсь 🤪, но я обещаю учиться дальше и стараться, чего и Вам желаю))

😎
Please open Telegram to view this post
VIEW IN TELEGRAM
💯3
Вот что мне написали в комментариях под последним видео:

@AlexSmile-y2x

В кратце могу накидать:
1) create:
в рест рекоммендациях указано каким долен быть create эндпоинт и это хорошие рекоммендации. Он долен возвращать path с айди созданной сущности в хедере Location респонса, а не созданную сущность (еще и скопированную в существующую ссылку, в каком то из твоих сервисов и такое было...)
2) read:
- никогда не используется получение всех сущностей из БД, это бесполезная и ресурсоемкая операция. Всегда возвращается конкретная необходимая часть данных.
- при получении данных всегда используется фильтрация, а по хорошему еще пагинация и сортировка. Это работа на пять минут (добавление пары аннотаций и пары классов), но это хотя бы реалистичный вариант findBy эндпоинта, а не синтетический и абсолютно бесполезный как тут.
- при получении данных плохо возвращать List, т.к. часто нуно дорабатывать метаданными респонс и придется костылить. Вместо этого проще сразу создать обертку, куда можно будет добавлять поля метаданных (а еще лучше использовать готовый вариант Page)
- если у тебя есть адекватный эндпоинт с фильтрацией, то тебе не понадобятся эндпоинты типа findByStatus, findByLogin etc. т.к. он сможет обрабатывать любой из таких запросов. Собственно именно так и делается обычно
3) update:
- апдейт вообще работает сейчас некорректно. Это по твоей логике сейчас PUT, а не PATCH (почитай про разницу, только у тебя вообще почему-то ожидается POST, что вообще невалидно для ReST), но даже если сменишь на PUT это крайне неудобно использовать в реале: Ты обязуешь клиента передавать всю сущность целиком для апдейта даже одного поля, а если он передаст только поле, котрое хочет изменить, то остальные поля станут null... и даже если ты поставишь
@NotNull constraint то тем самым не позволишь апдейтить nullable значения в бдю Вобщем апдей вообще не так реализуется, если интересно спроси как, я опишу детальнее (почитай про Json Merge Patch)
4) delete:
- проверка на наличие перед удалением избыточно, ты этим стреляешь сам себе в ногу: удаление должно быть идемпотентным (почитай что это такое)
- удалять все тоже стоит по фильтру (как при получении данных), тогда можно удалить несколько сущностей по айли, имени и т.п.
5) В целом по сервису:
- У тебя вообще отсутствует транзакционность. Это серьезная недоработка бэкенда.
- возвращай нормальные стутусы, иначе для чего тебе ResponseEntity? (201 для создания, 204 для удаления ит.п.)
- Нет смысла делать имплементацию публичной. Имплементации не выставляются наружу (есть интерфейс для этого, либо тогда нет смысла делать интерфейс)
- Есть смысл держать объекты максимально неизменяемыми (как минимум локальные переменные всегда должны быть final, это в перспективе позволяет отсечь огромное количество багов)
- маппинг эндпоинтов и набор параметров абсолютно рандомный. Есть стандарт ReST и RMM для работы с подобными API. Почитай про это (вкратце маппинг контроллера - имя ресурса во мн.числе, а маппинг эндпоинтов только id для findById, deleteById и update)
- именование пакетов всегда в единственном числе
- у тебя рест сервис, поэтому вместо ControllerAdvice лучше использовать RestControllerAdvice, а еще гибче использовать стартер спринга для exception-handling
- нет смысла ставить
@Repository, если интерфейс и так наследует Repository (Spring Boot Data Jpa component scan уже содержит фильтр по созданию компонентов для таких интерфейсов)
- оборачивать список в optional тоже бессмысленно, list сам по себе обертка (почитай для чего создавался optional и как он используется)
- использовать
@Resource из JSR-250 очень странно тут, учитывая, что у тебя Spring, надо использовать специфичные аннотации, это и более идеоматично и более гибко, т.к. вся подкапотная логика спринговая
- dto для создания, апдейта и возвращения результата всегда отличаются, это три разных типа должны быть (например OrderCreateDto, OrderUpdateDto, OrderGetDto, приставка Delivery избыточна, т.к. у тебя весь сервис и так delivery, это просто context duplication)
🤔2
- чем обусловлено использование стратегии генерации id по дополнительному запросу к сиквенс БД, если можно отдать это на откуп самой БД? (почитай как работают разные стратегии IdGeneratedValue)
- использование примитивом в качестве полей класса - дурная затея, т.к. они имеют дефолтное значение отличное от null, что может вести к непредсказуемым сценариям, стоит всегда использовать обертки (исключение разве что boolean, где дефолтное значение false может быть приемлемо иногда)
- списки в качестве полей класса всегда надо инициализировать иначе будешь падать с NPE в неожиданных местах
- для операций с деньгами вообще никто не использует integer, это во-первых всегда дробное значение, а во-вторых оно должно быть точным, это должен быть BigDecimal
- many-to-many связь гораздо удобнее описывать на уровне логики в виде линкующей сущности и соответственно one-to-many связи к ней, это очень сильно упрощает работу в дальнейшем
- использование
@Data над entity - плохая практика, лучше задавать отдельно аксессоры и переопределение equals (это как минимум дает возможность исключить из генерации хэша нежелательные поля(всякий аудит, циклические ссылки и т.п.), да и в целом дает больший контроль и позволяет в дальнейшем избежать косяков из-за недостатка инкапсуляции)
- имена переменных не должны содержать информацию о типе, это очень нетипично для Джава, как для строго типизированного языка. Именование содерит информацию о свойстве и его значении, а не о типе (например не ..UUUID, а ...Id etc.)
- также нет никакой валидации, логирования и т.п. но это уже дополнительная логика, а я пишу по текущей

А вообще в целом, молодец, что такие видео пилишь, Java хороший язык в очень многих аспектах. Респектуха. Только старайся улучшать качество кода ;)
👍2🤔1
📌 Факт дня:

"А вы знали что... первые компьютеры хранили данные на перфокартах?"

Представьте себе, что вместо флешки вам нужно было бы использовать картонные карточки с дырками! Такие устройства использовались еще в 1890 году для переписи населения США.


#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
😱2😁1
✏️ Цитата дня: Билл Гейтс

"Успех — это плохой учитель. Он заставляет умных людей думать, что они не могут проиграть."


Билл Гейтс сказал эту фразу в своей книге "Дорога в будущее" (1995). Она подчеркивает важность постоянного обучения и осторожности даже при достижении успеха.

Почитать короткую биографию

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Создание объектов через Reflection

Reflection (отражение) в Java — это механизм, который позволяет анализировать и изменять поведение классов, методов, полей и других элементов программы во время выполнения. Это мощный инструмент, но он требует осторожности, так как может привести к снижению производительности и усложнению кода.

1. Использование Class.newInstance() (устаревший метод)

Метод Class.newInstance() был одним из первых способов создания объектов через Reflection. Он позволяет создать экземпляр класса, используя его пустой конструктор (конструктор без аргументов).

Как это работает:
Вы получаете объект Class с помощью Class.forName("полное.имя.класса").
Затем вызываете метод newInstance(), который создает объект.


Пример кода:
public class MyClass {
public MyClass() {
System.out.println("Объект MyClass создан!");
}
}

public class ReflectionExample {
public static void main(String[] args) {
try {
// Получаем объект Class
Class<?> clazz = Class.forName("MyClass");

// Создаем объект через newInstance()
MyClass obj = (MyClass) clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}


Плюсы:
Простота использования.
Не требует явного указания конструктора.


Минусы:
Устаревший метод (начиная с Java 9, он считается deprecated).
Работает только с классами, у которых есть публичный конструктор без аргументов.
Не поддерживает передачу параметров в конструктор.


Под капотом:
Метод newInstance() внутри вызывает getDeclaredConstructor() для получения конструктора без аргументов, а затем вызывает Constructor.newInstance().

2. Использование Constructor.newInstance()

Этот метод является более гибким и современным способом создания объектов через Reflection. Он позволяет использовать любой конструктор, включая те, которые принимают аргументы.

Как это работает:
Вы получаете объект Class.
С помощью метода getDeclaredConstructor() получаете конкретный конструктор.
Вызываете метод newInstance() у объекта Constructor, передавая необходимые аргументы.


Пример кода:
public class MyClass {
private String name;

public MyClass(String name) {
this.name = name;
System.out.println("Объект MyClass создан с именем: " + name);
}
}

public class ReflectionExample {
public static void main(String[] args) {
try {
// Получаем объект Class
Class<?> clazz = Class.forName("MyClass");

// Получаем конструктор с параметром String
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);

// Создаем объект через newInstance()
MyClass obj = (MyClass) constructor.newInstance("John");
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}


Плюсы:
Поддерживает конструкторы с параметрами.
Более гибкий и мощный, чем Class.newInstance().
Не deprecated.


Минусы:
Требует больше кода для получения конструктора.
Может выбросить исключения, если конструктор недоступен или параметры не совпадают.


Под капотом:

Метод newInstance() внутри вызывает нативный метод, который выделяет память для объекта и инициализирует его с помощью переданного конструктора.

#Java #Training #Medium #Reflection_API #Constructor_newInstance
👍31
Что выведет код?

public class Task110225 {
public static void main(String[] args) {
String s = "hello";
switch (s) {
case "hello":
System.out.print("A");
case "world":
System.out.print("B");
default:
System.out.print("C");
}
}
}


#Tasks
👍1
Варианты ответа:
Anonymous Quiz
51%
A
3%
AB
38%
ABC
8%
RuntimeException
👍1
Ну хоть леща не прописывает... Пока... 😁

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Вызов методов через Reflection

Теперь перейдем к вызову методов через Reflection. Это полезно, когда вы хотите вызвать метод, имя которого неизвестно до момента выполнения программы.

1. Использование Method.invoke() для вызова методов

Метод Method.invoke() позволяет вызывать методы объекта динамически. Вы можете получить объект Method с помощью getDeclaredMethod() или getMethod(), а затем вызвать его.

Как это работает:
Вы получаете объект Class.
С помощью getDeclaredMethod() или getMethod() получаете объект Method.
Вызываете метод invoke(), передавая объект и аргументы.


Пример кода:
public class MyClass {
public void sayHello(String name) {
System.out.println("Привет, " + name + "!");
}
}

public class ReflectionExample {
public static void main(String[] args) {
try {
// Получаем объект Class
Class<?> clazz = Class.forName("MyClass");

// Создаем объект
Object obj = clazz.getDeclaredConstructor().newInstance();

// Получаем метод sayHello с параметром String
Method method = clazz.getDeclaredMethod("sayHello", String.class);

// Вызываем метод
method.invoke(obj, "John");
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}


Плюсы:
Позволяет вызывать методы динамически.
Поддерживает методы с параметрами.


Минусы:
Медленнее, чем прямой вызов метода.
Может выбросить исключения, если метод недоступен или параметры не совпадают.


Под капотом:
Метод invoke() использует нативные вызовы для выполнения метода. Это требует дополнительных проверок и может привести к снижению производительности.

2. Обработка исключений при вызове методов

При работе с Reflection важно правильно обрабатывать исключения.

Основные исключения, которые могут возникнуть:
IllegalAccessException: если метод недоступен (например, он private).
InvocationTargetException: если метод выбросил исключение.
NoSuchMethodException: если метод не найден.


Пример обработки исключений:
try {
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.setAccessible(true); // Разрешаем доступ к private методам
method.invoke(obj, "John");
} catch (NoSuchMethodException e) {
System.out.println("Метод не найден: " + e.getMessage());
} catch (IllegalAccessException e) {
System.out.println("Нет доступа к методу: " + e.getMessage());
} catch (InvocationTargetException e) {
System.out.println("Метод выбросил исключение: " + e.getCause().getMessage());
}


Плюсы:
Позволяет безопасно работать с Reflection.
Помогает отлаживать проблемы.


Минусы:
Увеличивает объем кода.
Требует внимательности при обработке исключений.


#Java #Training #Medium #Reflection_API #Method_invoke
👍1
✏️ Цитата дня: Эндрю Ын

"AI — новое электричество."


Профессор Стэнфорда Эндрю Ын сказал это во время лекции в 2017 году, подчеркивая революционное влияние ИИ на все сферы жизни.

Почитать короткую биографию

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📌 Факт дня:

"А вы знали что... есть универсальный язык аннотации и представления настроений в программировании, который работает на основе эмоций?"

Он называется Emotion Machine (EML или EmotionML) и позволяет программировать с помощью таких команд, как 'happy', 'sad', и 'angry'.
Сложно представить, но этот язык реально существует!


Proof

#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔3🔥1
Введение в модульность и история Java Platform Module System — JPMS

Модульность — это принцип проектирования программного обеспечения, при котором система разбивается на отдельные, независимые компоненты (модули). Каждый модуль инкапсулирует определенную функциональность и взаимодействует с другими модулями через четко определенные интерфейсы.

Зачем нужна модульность?


Управление зависимостями: Модульность позволяет явно указывать, какие модули зависят от других, что упрощает управление зависимостями и предотвращает конфликты.
Изоляция кода: Модули изолируют код, что уменьшает вероятность непреднамеренного взаимодействия между частями системы.
Улучшение производительности: Модульность позволяет загружать только те части приложения, которые действительно нужны, что может улучшить производительность и уменьшить использование памяти.


Проблемы, которые решает модульность

До появления модульности в Java разработчики сталкивались с несколькими проблемами:
JAR Hell: Конфликты версий библиотек из-за отсутствия четкого управления зависимостями.
Отсутствие инкапсуляции: Все классы в classpath были доступны друг другу, что могло привести к непреднамеренному использованию внутренних API.
Большие размеры приложений: Приложения включали все библиотеки, даже если они не использовались, что увеличивало размер и время запуска.


История появления JPMS (Java Platform Module System)

Java Platform Module System (JPMS), также известный как Project Jigsaw, был введен в Java 9 для решения вышеупомянутых проблем.

JPMS добавил в Java поддержку модульности на уровне языка, что позволило:
Разделять JDK на модули, что уменьшило размер runtime-окружения.
Управлять зависимостями на уровне модулей.
Улучшить безопасность и производительность за счет инкапсуляции.


Основные концепции

Модуль (module) как единица инкапсуляции
Модуль в Java — это набор пакетов, который может быть скомпилирован и запущен независимо. Модуль определяет, какие пакеты он экспортирует (делает доступными для других модулей) и какие модули ему необходимы для работы.
Файл
module-info.java — его структура и назначение
Каждый модуль должен содержать файл
module-info.java, который описывает его структуру и зависимости. Этот файл находится в корне модуля и содержит директивы, определяющие, какие пакеты экспортируются, какие модули требуются и т.д.

Пример простого модуля:
module com.example.myapp {
requires java.base; // Зависимость от базового модуля Java
exports com.example.myapp.api; // Экспорт пакета com.example.myapp.api
}
В этом примере модуль com.example.myapp зависит от базового модуля java.base и экспортирует пакет com.example.myapp.api.


#Java #Training #Medium #JPMS
👍1
Что выведет код?

import java.util.function.Function;

public class Task120225 {
public static void main(String[] args) {
Function<String, String> func1 = String::toUpperCase;
Function<String, String> func2 = s -> s.toUpperCase();

String result1 = func1.apply("hello");
String result2 = func2.apply("hello");

System.out.println(result1 == result2);
}
}


#Tasks
👍1