Java | Фишки и трюки
7.21K subscribers
182 photos
29 videos
6 files
40 links
Java: примеры кода, интересные фишки и полезные трюки

Купить рекламу: https://telega.in/c/java_tips_and_tricks

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Почему String неизменяемый класс?

Есть несколько преимуществ в неизменности строк:

✔️ Пул строк возможен только потому, что строка неизменяемая, таким образом виртуальная машина сохраняет больше свободного места в Heap, поскольку разные строковые переменные указывают на одну и ту же переменную в пуле. Если бы строка была изменяемой, то интернирование строк не было бы возможным, потому что изменение значения одной переменной отразилось бы также и на остальных переменных, ссылающихся на эту строку.

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

✔️ Неизменяемость позволяет избежать синхронизации: строки безопасны для многопоточности и один экземпляр строки может быть совместно использован различными потоками.

✔️ Строки используются classloader и неизменность обеспечивает правильность загрузки класса.

✔️ Поскольку строка неизменяемая, её hashCode() кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в HashMap т.к. его обработка происходит быстрее.

#java #string #immutable
Please open Telegram to view this post
VIEW IN TELEGRAM
👍171
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Quest {
public static void main(String[] args) {
List<String> list = Stream.of("Pizza", "Sushi", "Pasta", "Sushi", "Pizza")
.sequential()
.filter(new TreeSet<>()::add)
.collect(Collectors.toList());
System.out.println(list);
}
}
4👏2😐2😭2😡1
⌨️ Неизменяемые коллекции

Для получения неизменяемого варианта коллекции, в классе Collections есть соответствующие методы:

unmodifiableCollection
unmodifiableSequencedCollection
unmodifiableSet
unmodifiableSequencedSet
unmodifiableSortedSet
unmodifiableNavigableSet
unmodifiableList
unmodifiableMap
unmodifiableSequencedMap
unmodifiableSortedMap
unmodifiableNavigableMap

Поскольку неизменяемые коллекции нельзя изменить, разработчики могут быть уверены, что состояние коллекции не будет неожиданно изменено в других частях программы.

В некоторых случаях неизменяемые коллекции могут повышать производительность, так как операции над такими коллекциями не требуют блокировок и синхронизации.


List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
List<String> unmodifiableList = Collections.unmodifiableList(list);
// Попытка изменить unmodifiableList приведет к UnsupportedOperationException
// unmodifiableList.remove("B");


#java #collections #immutable #unmodifiable
Please open Telegram to view this post
VIEW IN TELEGRAM
👌6👍4🔥2
😁19👍4🤣4💔2🙈1
Stream

Все операции Stream делятся на промежуточные и терминальные и объединяются в потоковые конвейеры.

Потоковый конвейер состоит из источника (например, коллекции, массива, функции-генератора, канала ввода-вывода или генератора бесконечной последовательности) за которым следует ноль или более промежуточных операций и терминальной операции.

Промежуточные операции
📌 Промежуточные операции не выполняются до тех пор, пока не будет вызвана какая-либо терминальная операция.

Они составляют конвейер выполнения Stream. Промежуточную операцию можно добавить в конвейер Stream методами:
filter()
map()
flatMap()
distinct()
sorted()
peek()
limit()
skip()


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

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

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

Это очень важное свойство, особенно важное для бесконечных потоков, поскольку оно позволяет нам создавать потоки, которые будут фактически вызываться только при вызове терминальной операции.

Терминальные операции
Терминальные операции могут проходить через поток для получения результата или побочного эффекта.

📌 После выполнения терминальной операции, потоковый конвейер считается использованным и больше не может использоваться.

Терминальные операции:
forEach()
forEachOrdered()
toArray()
reduce()
collect()
min()
max()
count()
anyMatch()
allMatch()
noneMatch()
findFirst()
findAny()


Каждая из этих операций инициирует выполнение всех промежуточных операций.
👍182🔥1👏1
🧩 Комбинирование предикатов

Predicate - встроенный функциональный интерфейс, добавленный в Java 8 в пакет java.util.function.

Принимает на вход значение, проверяет состояние и возвращает boolean значение в качестве результата.

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

У предиката есть 3 default метода для составления условия. Имена методов говорящие: and(), or(), negate()
👍8🔥2
⌨️ Что такое класс Object? Какие в нем есть методы?

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
👍15🔥2🥱1
⌨️ Зачем нужен equals(). Чем он отличается от операции ==?

Метод equals() - определяет отношение эквивалентности объектов.

При сравнении объектов с помощью == сравнение происходит лишь между ссылками. При сравнении по переопределённому разработчиком equals() - по внутреннему состоянию объектов.

#java #equals
Please open Telegram to view this post
VIEW IN TELEGRAM
👍121🥱1
⌨️ Контракт метода equals()

✔️ Рефлексивность: для любой ссылки на значение x, x.equals(x) вернет true;

✔️ Симметричность: для любых ссылок на значения x и y, x.equals(y) должно вернуть true, тогда и только тогда, когда y.equals(x) возвращает true.

✔️ Транзитивность: для любых ссылок на значения x, y и z, если x.equals(y) и y.equals(z) возвращают true, тогда и x.equals(z) вернёт true;

✔️ Непротиворечивость: для любых ссылок на значения х и у, если несколько раз вызвать х.equals(y), постоянно будет возвращаться значение true либо постоянно будет возвращаться значение false при условии, что никакая информация, используемая при сравнении объектов, не поменялась.

❗️Для любой ненулевой ссылки на значение х выражение х.equals(null) должно возвращать false.

#java #equals #contract
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥51
⌨️ instanceof или getClass() == ...

Часто нам нужно проверить является ли объект экземпляром определенного класса, например в методе 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👍5
😁25🤣11🥱2
public class Quest {
public static void main(String[] args) {
int x = 5;
int y = 8;

if (x++ > 5 && ++y > 8) {
x++;
}

System.out.println("x = " + x + ", y = " + y);
}
}

#java #quest
🔥1
🔥1
⌨️ Поддержка лямбда выражений в своём коде

В 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
👍172🔥2
public class Quest {
public static void main(String[] args) {
int x = 5;
int y = 10;
x = x++ + ++y;
System.out.println("x = " + x + ", y = " + y);
}
}

#java #quest
🎉4👍31
⌨️ Для чего нужен метод hashCode()?

Метод hashCode() необходим для вычисления хэш кода переданного в качестве входного параметра объекта. В Java это целое число, в более широком смысле - битовая строка фиксированной длины, полученная из массива произвольной длины. Этот метод реализован таким образом, что для одного и того же входного объекта, хэш код всегда будет одинаковым. Следует понимать, что в Java множество возможных хэш кодов ограничено типом int, а множество объектов ничем не ограничено. Из-за этого, вполне возможна ситуация, что хэш коды разных объектов могут совпасть:

✔️ если хэш коды разные, то и объекты гарантированно разные;

✔️ если хэш коды равны, то объекты не обязательно равны(могут быть разные).

#java #hashCode
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍3
⌨️ Лямбда-выражения и свой кастомный функциональный интерфейс

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

@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}

Функциональный интерфейс MathOperation содержит один абстрактный метод operate, который принимает два значения типа int и возвращает int. Аннотация @FunctionalInterface указывает на то, что интерфейс предназначен для использования в функциональном программировании и должен содержать только один абстрактный метод. Но аннотация не обязательна.

Использование лямбда-выражения:

public class LambdaExample {
public static void main(String[] args) {
// Реализация интерфейса с помощью лямбда-выражения
MathOperation addition = (a, b) -> a + b;
MathOperation subtraction = (a, b) -> a - b;
MathOperation multiplication = (a, b) -> a * b;
MathOperation division = (a, b) -> a / b;

int x = 10;
int y = 5;

System.out.println("Addition: " + operate(x, y, addition)); // 15
System.out.println("Subtraction: " + operate(x, y, subtraction)); // 5
System.out.println("Multiplication: " + operate(x, y, multiplication)); // 50
System.out.println("Division: " + operate(x, y, division)); // 2
}

// Метод, принимающий MathOperation и применяющий его к данным
private static int operate(int a, int b, MathOperation operation) {
return operation.operate(a, b);
}
}


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

Метод operate принимает два целых числа и функциональный интерфейс MathOperation, затем выполняет переданную операцию. В метод в третьем параметре можно передать непосредственно лямбда-выражение, не используя промежуточную переменную.

#java #lambda #FunctionalInterface
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍19❤‍🔥21
🤯3😱1