// Для импорта конкретного статического члена
import static package.Clazz.member;
// Для импорта всех статических членов класса
import static package.Clazz.*;
Пример:
public class MathUtils {
public static final double PI = 3.141592653589793;
public static int add(int a, int b) {
return a + b;
}
public static int subtract(int a, int b) {
return a - b;
}
}
import static MathUtils.PI;
import static MathUtils.add;
public class Main {
public static void main(String[] args) {
System.out.println("Value of PI: " + PI);
System.out.println("Addition result: " + add(5, 3));
}
}
import static MathUtils.*;
public class Main {
public static void main(String[] args) {
System.out.println("Value of PI: " + PI);
System.out.println("Addition result: " + add(5, 3));
System.out.println("Subtraction result: " + subtract(5, 3));
}
}
Плюсы: читаемость, компактность кода.
Минусы:
- не очевидно откуда берется поле или метод
- импорт всех статических членов может привести к конфликтам имен, если разные классы содержат статические члены с одинаковыми именами
#java #static #import
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥4❤1
Часто нам нужно проверить является ли объект экземпляром определенного класса, например в методе equals(). Существует несколько способов это сделать. Разберём два из них.
instanceof проверяет, является ли ссылка на объект в левой части экземпляром типа в правой части или каким-либо подтипом.
getClass() == ... проверяет, идентичны ли типы.
Выбирать способ проверки типа нужно исходя из решаемой задачи. В методе equals() можно использовать оба способа в зависимости от того собираетесь ли вы позволять сравнивать объект определенного класса и объект класса наследника.
class Parent { }
class Child extends Parent { }
public class Test {
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
System.out.println(parent instanceof Parent); // true
System.out.println(child instanceof Parent); // true
System.out.println(parent.getClass() == Parent.class); // true
System.out.println(child.getClass() == Parent.class); // false
}
}
#java #instanceof #getClass
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤4
Есть несколько видов ссылок на методы:
1️⃣ Ссылка на статический метод
Используется для вызова статических методов класса.
Синтаксис:
ContainingClass::staticMethodName
Пример:
import java.util.function.Function;
public class MethodReferenceExample {
public static void main(String[] args) {
Function<String, Integer> converter = Integer::parseInt;
Integer number = converter.apply("123");
System.out.println(number); // 123
}
}
2️⃣ Ссылка на метод экземпляра конкретного объекта
Используется для вызова методов экземпляра объекта.
Синтаксис:
containingObject::instanceMethodName
Пример:
import java.util.Arrays;
import java.util.List;
public class MethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);
}
}
3️⃣ Ссылка на метод экземпляра произвольного объекта определенного типа
Синтаксис:
ContainingType::methodName
Пример:
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> stringLength = String::length;
Integer length = stringLength.apply("Hello, World!");
System.out.println(length); // 13
}
}
Отличие от предыдущего вида в том, что в предыдущем ссылка на метод получается у конкретного объекта, стало быть вызовется метод этого объекта, а в нашем случае при получении ссылки на метод, мы знаем только метод, но объект у которого вызовется этот метод еще не известен, он будет предоставлен при вызове метода. Код выше будет означать "Hello, World!".length()
4️⃣ Ссылка на конструктор
Используется для вызова конструктора.
Синтаксис:
ClassName::new
Пример:
import java.util.function.Supplier;
public class MethodReferenceExample {
public static void main(String[] args) {
Supplier<MethodReferenceExample> exampleSupplier = MethodReferenceExample::new;
MethodReferenceExample example = exampleSupplier.get();
System.out.println(example); // MethodReferenceExample@<hashcode>
}
}
#java #MethodReference
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4
Цикл for со счетчиком
for (initialization; condition; update) {
// тело цикла
}
Описание:
initialization: выполняется один раз перед началом цикла. Обычно используется для инициализации счетчика.
condition: проверяется перед каждой итерацией. Если условие истинно, выполняется тело цикла.
update: выполняется после каждой итерации. Обычно используется для изменения счетчика.
int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < numbers.length; i++) {
System.out.println(i + ": " + numbers[i]);
}
Применение:
Используется, когда известно количество итераций заранее. Часто применяется для работы с массивами или коллекциями, когда нужен индекс.
Цикл for-each
for (type element : collection) {
// тело цикла
}
Описание:
Итерируется по каждому элементу коллекции (например, массива, списка, множества). Обеспечивает удобный способ доступа к каждому элементу без использования индексов.
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}
Применение:
Предпочтителен, когда не нужен доступ к индексам элементов.
Цикл while
while (condition) {
// тело цикла
}
Описание:
condition: проверяется перед каждой итерацией. Если условие истинно, выполняется тело цикла.
String code = UUID.randomUUID().toString();
boolean isCodeExists = repo.isCodeExists(code);
while (isCodeExists) {
code = UUID.randomUUID().toString();
isCodeExists = repo.isCodeExists(code);
}
repo.saveCode(code);
Применение:
Используется, когда количество итераций неизвестно заранее и определяется во время выполнения программы. Цикл может не выполниться ни одного раза.
Цикл do-while
do {
// тело цикла
} while (condition);
Описание:
Выполняет тело цикла хотя бы один раз, а затем проверяет условие condition. Если условие истинно, цикл повторяется.
String command;
do {
command = readCommand();
doCommand(command);
} while (!"EXIT".equals(command));
Применение:
Используется, когда тело цикла должно выполниться хотя бы один раз, независимо от условия. Часто применяется для меню или ввода данных, где сначала нужно выполнить действие, а затем проверить условие.
#java #cycles #for #while
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1
Heap (куча) используется Java Runtime для выделения памяти под объекты и классы. Создание нового объекта также происходит в куче. Это же является областью работы сборщика мусора. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться из любой части приложения.
Stack (стек) это область хранения данных также находящееся в общей оперативной памяти (RAM). Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе. Как только метод заканчивает работу, блок также перестает использоваться, тем самым предоставляя доступ для следующего метода. Размер стековой памяти намного меньше объема памяти в куче. Стек в Java работает по схеме LIFO (Последний-зашел-Первый-вышел)
Различия между Heap и Stack памятью:
✔️ Куча используется всеми частями приложения, в то время как стек используется только одним потоком исполнения программы.
✔️ Всякий раз, когда создается объект, он всегда хранится в куче, а в памяти стека содержится лишь ссылка на него. Память стека содержит только локальные переменные примитивных типов и ссылки на объекты в куче.
✔️ Объекты в куче доступны с любой точки программы, в то время как стековая память не может быть доступна для других потоков.
✔️ Стековая память существует лишь какое-то время работы программы, а память в куче живет с самого начала до конца работы программы.
✔️ Если память стека полностью занята, то Java Runtime бросает исключение java.lang.StackOverflowError. Если заполнена память кучи, то бросается исключение java.lang.OutOfMemoryError: Java Heap Space.
✔️ Размер памяти стека намного меньше памяти в куче.
✔️ Из-за простоты распределения памяти, стековая память работает намного быстрее кучи.
Для определения начального и максимального размера памяти в куче используются -Xms и -Xmx опции JVM. Для стека определить размер памяти можно с помощью опции -Xss.
#java #heap #stack #memory
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2🔥1
В Java 12 появился новый синтаксис для
switch, который позволяет возвращать значение используя стрелки ->, что делает код более компактным и удобным. Теперь switch может использоваться как выражение, а не только как оператор, что упрощает его применение в логике.Ранее
switch использовался как оператор, и код мог выглядеть громоздко:
String day = "MONDAY";
int numLetters;
switch (day) {
case "MONDAY":
case "FRIDAY":
case "SUNDAY":
numLetters = 6;
break;
case "TUESDAY":
numLetters = 7;
break;
default:
numLetters = 8;
}
System.out.println(numLetters); // Вывод: 6
Со Switch Expressions можно переписать этот код более лаконично:
String day = "MONDAY";
int numLetters = switch (day) {
case "MONDAY", "FRIDAY", "SUNDAY" -> 6;
case "TUESDAY" -> 7;
default -> 8;
};
System.out.println(numLetters); // Вывод: 6
Теперь
switch может вернуть значение, и нет необходимости в break.#java #switch
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22❤3
Общий совет: выбирать поля, которые с большой долью вероятности будут различаться. Для этого необходимо использовать уникальные, лучше всего примитивные поля, например, такие как id, uuid. При этом нужно следовать правилу, если поля задействованы при вычислении
hashCode(), то они должны быть задействованы и при выполнении equals().#java #hashCode #equals
Please open Telegram to view this post
VIEW IN TELEGRAM
👨💻6❤2
В Java лямбда-выражения используются с функциональными интерфейсами, которые имеют ровно один абстрактный метод. Например, стандартный функциональный интерфейс
Function из пакета java.util.function представляет собой типичный пример.Для нашего примера используем встроенный функциональный интерфейс
IntUnaryOperator. Он выглядит вот так:
@FunctionalInterface
public interface IntUnaryOperator {
int applyAsInt(int operand);
}
Этот интерфейс представляет функцию, которая принимает один аргумент типа
int и возвращает значение типа int.
import java.util.function.IntUnaryOperator;
public class Main {
public static int applyOperation(int number, IntUnaryOperator operator) {
return operator.applyAsInt(number);
}
public static void main(String[] args) {
int number = 5;
// Лямбда-выражение для удвоения значения
IntUnaryOperator doubleOperation = x -> x * 2;
System.out.println("Double: " + applyOperation(number, doubleOperation)); // Double: 10
// Лямбда-выражение для увеличения значения на 10
IntUnaryOperator addTenOperation = x -> x + 10;
System.out.println("Add Ten: " + applyOperation(number, addTenOperation)); // Add Ten: 15
}
}
В нашем примере метод
applyOperation принимает два параметра: число и функциональный интерфейс IntUnaryOperator. Лямбда-выражение используется для определения конкретной функции.#java #lambda #IntUnaryOperator
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2
Object это базовый класс для всех остальных объектов в Java. Любой класс наследуется от Object и, соответственно, наследуют его методы:public boolean equals(Object obj) – служит для сравнения объектов по значению;int hashCode() – возвращает hash код для объекта;String toString() – возвращает строковое представление объекта;Class getClass() – возвращает класс объекта во время выполнения;protected Object clone() – создает и возвращает копию объекта;void notify() – возобновляет поток, ожидающий монитор;void notifyAll() – возобновляет все потоки, ожидающие монитор;void wait() – остановка вызвавшего метод потока до момента пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;void wait(long timeout) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;void wait(long timeout, int nanos) – остановка вызвавшего метод потока на определённое время или пока другой поток не вызовет метод notify() или notifyAll() для этого объекта;protected void finalize() – может вызываться сборщиком мусора в момент удаления объекта при сборке мусора.#java #Object #methods
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
Дан список людей с именем и городом проживания. Нужно сгруппировать их по городам.
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
record Person(String name, String city) {}
public class StreamExample {
public static void main(String[] args) {
List<Person> people = List.of(
new Person("Alice", "New York"),
new Person("Bob", "Los Angeles"),
new Person("Charlie", "New York"),
new Person("David", "Los Angeles"),
new Person("Edward", "San Francisco")
);
Map<String, List<Person>> peopleByCity = people.stream()
.collect(Collectors.groupingBy(Person::city));
peopleByCity.forEach((city, peopleInCity) -> {
System.out.println(city + ": " + peopleInCity.stream()
.map(Person::name)
.collect(Collectors.joining(", ")));
});
// Вывод:
// San Francisco: Edward
// New York: Alice, Charlie
// Los Angeles: Bob, David
}
}
#java #stream #grouping
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍14🔥4❤3
В микросервисной архитектуре наблюдаемость — не роскошь, а умение выжить в проде. Как сделать качественный мониторинг без затратных решений? Ответ в новой статье от Anderson Kuntz Meurer.
@RestController к метрикам — HTTP‑статы, latency, ошибки.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Maven использует жизненный цикл сборки, который делится на несколько фаз. Фазы определяют последовательность задач, которые Maven выполняет для сборки и управления проектом.
Основные фазы жизненного цикла Maven включают:
1️⃣ validate – Проверяет, что проект правильный и вся необходимая информация указана.
2️⃣ compile – Компилирует исходный код проекта.
3️⃣ test – Запускает тесты (обычно с использованием JUnit или TestNG) и проверяет, что они проходят успешно.
4️⃣ package – Собирает скомпилированный код и пакует его, например, в JAR или WAR-файл.
5️⃣ verify – Проверяет собранные артефакты и результаты тестов.
6️⃣ install – Устанавливает пакет в локальный репозиторий для использования как зависимость в других проектах.
7️⃣ deploy – Отправляет финальный пакет в удаленный репозиторий для использования в других проектах или на сервере.
Основные команды Maven:
✔️
mvn clean – Удаляет папку target, очищая проект от предыдущих сборок.✔️
mvn compile – Компилирует исходный код проекта.✔️
mvn test – Запускает тесты.✔️
mvn package – Пакует скомпилированный код в конечный артефакт (обычно JAR или WAR).✔️
mvn install – Устанавливает артефакт в локальный репозиторий.✔️
mvn deploy – Деплоит артефакт в удаленный репозиторий.✔️
mvn site – Генерирует документацию проекта на основе кода и зависимостей.Фазы выполняются последовательно, то есть если вы запускаете команду
mvn install, Maven автоматически пройдет через все предыдущие фазы – от validate до install.Примеры команд:
✔️
mvn clean install – очищает проект, компилирует, тестирует и устанавливает артефакт в локальный репозиторий.✔️
mvn package -DskipTests – собирает проект в артефакт, пропуская тесты.#java #Maven
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤3🔥3
Дженерики позволяют определить параметр типа, который будет заменен конкретным типом данных при создании экземпляра класса или вызове метода. Например,
List<T> может использоваться как List<String>, List<Integer> и т.д.Благодаря дженерикам, ошибки типа (например, попытка вставить объект неправильного типа) обнаруживаются на этапе компиляции, а не во время выполнения программы.
Один универсальный класс или метод может работать с различными типами данных, что позволяет избежать дублирования кода.
Во время компиляции информация о типах стирается, и вместо этого используется базовый тип, что позволяет сохранять совместимость с кодом, написанным до появления дженериков.
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String str = stringBox.getItem();
В этом примере класс
Box<T> является обобщенным и может работать с любым типом данных, который заменит T при создании объекта.#java #generics #T
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤5🔥4
java.util. Он облегчает создание текстовых последовательностей, объединяя строки и вставляя разделители между ними.Вызов метода
toString() возвращает объединенную строку с разделителями и окружающими символами.Вы также можете использовать метод
setEmptyValue() для определения значения, которое будет использоваться, если StringJoiner остается пустым.
StringJoiner sj = new StringJoiner(", ", "[" , "]");
sj.setEmptyValue("No items");
System.out.println(sj.toString()); // No items
sj.add("Apple").add("Banana").add("Cherry");
System.out.println(sj.toString()); // [Apple, Banana, Cherry]
#java #StringJoiner
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9🔥4
Java является строго типизированным языком программирования, а это означает, то что каждое выражение и каждая переменная имеет строго определенный тип уже на момент компиляции. Однако определен механизм приведения типов (casting) - способ преобразования значения переменной одного типа в значение другого типа.
В Java существуют несколько разновидностей приведения:
✔️ Тождественное (identity). Преобразование выражения любого типа к точно такому же типу всегда допустимо и происходит автоматически.
✔️ Расширение (повышение, upcasting) примитивного типа (widening primitive). Означает, что осуществляется переход от менее емкого типа к более ёмкому. Например, от типа
byte (длина 1 байт) к типу int (длина 4 байта). Такие преобразование безопасны в том смысле, что новый тип всегда гарантировано вмещает в себя все данные, которые хранились в старом типе и таким образом не происходит потери данных. Этот тип приведения всегда допустим и происходит автоматически.✔️ Сужение (понижение, downcasting) примитивного типа (narrowing primitive). Означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные. Например, если число типа
int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны. В Java такое преобразование должно совершаться явным образом, при этом все старшие биты, не умещающиеся в новом типе, просто отбрасываются - никакого округления или других действий для получения более корректного результата не производится.✔️ Расширение объектного типа (widening reference). Означает неявное восходящее приведение типов или переход от более конкретного типа к менее конкретному, т.е. переход от потомка к предку. Разрешено всегда и происходит автоматически.
✔️ Сужение объектного типа (narrowing reference). Означает нисходящее приведение, то есть приведение от предка к потомку (подтипу). Возможно только если исходная переменная является подтипом приводимого типа. При несоответствии типов в момент выполнения выбрасывается исключение
ClassCastException. Требует явного указания типа.✔️ Преобразование к строке (to String). Любой тип может быть приведен к строке, т.е. к экземпляру класса
String.✔️ Запрещенные преобразования (forbidden). Не все приведения между произвольными типами допустимы. Например, к запрещенным преобразованиям относятся приведения от любого ссылочного типа к примитивному и наоборот (кроме преобразования к строке). Кроме того, невозможно привести друг к другу классы, находящиеся на разных ветвях дерева наследования и т.п.
При приведении ссылочных типов с самим объектом ничего не происходит, - меняется лишь тип ссылки, через которую происходит обращение к объекту.
Для проверки возможности приведения нужно воспользоваться оператором
instanceof:
Parent parent = new Child();
if (parent instanceof Child) {
Child child = (Child) parent;
}
#java #casting #upcasting #downcasting
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤3🔥2