Метод peek() возвращает поток, состоящий из элементов этого потока, дополнительно выполняя предусмотренное действие над каждым элементом по мере потребления элементов из результирующего потока.
Это промежуточная операция.
Для конвейеров параллельных потоков действие может быть вызвано в любое время и в любом потоке, в котором элемент становится доступным в результате вышестоящей операции. Если действие изменяет общее состояние, оно отвечает за обеспечение необходимой синхронизации.
Этот метод существует в основном для отладки, когда вы хотите видеть элементы по мере их прохождения через определенную точку конвейера:
Stream.of("one", "two", "three", "four")
.filter(e -> e. length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
// Filtered value: three
// Mapped value: THREE
// Filtered value: four
// Mapped value: FOUR
В тех случаях, когда реализация потока может оптимизировать создание некоторых или всех элементов (например findFirst или count), действие не будет вызываться для этих элементов.
#java #stream #peek
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤1
Понятия "оператор" и "операнд" играют ключевую роль в построении выражений и выполнении операций.
Оператор — это специальный символ или ключевое слово, которое указывает на выполнение определенного действия. Операторы используются для выполнения операций над переменными и значениями.
В Java существует несколько типов операторов:
✔️ Арифметические операторы
✔️ Операторы присваивания
✔️ Операторы сравнения
✔️ Логические операторы
✔️ Побитовые операторы
✔️ Операторы инкремента и декремента
Операнд — это элемент, над которым оператор выполняет действие. Операнды могут быть переменными, константами или результатами других выражений.
Примеры:
👉 В выражении a + b операнды это a и b, а оператор +.
👉 В выражении x = 5 операнды это x и 5, а оператор =.
👉 В выражении count++ операнд это count, а оператор ++.
#java #operator #operand
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3❤1
Тут разработчики не стали мудрствовать лукаво и просто использовали экземпляр
HashMap внутри HashSet. Каждый элемент HashSet хранится как ключ в этой хэш-таблице, а значение для каждого ключа установлено в фиксированное значение PRESENT, что является специальным объектом (обычно new Object()).При добавлении элемента, у него вычисляется хэш-код, определяется соответствующий бакет, и элемент добавляется в этот бакет, если он еще не присутствует (проверяется с помощью метода
equals()).При удалении вычисляется хэш-код элемента, определяется бакет, и элемент удаляется, если он присутствует в этом бакете.
Упрощённый код класса HashSet:
public class HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
// Внутренний экземпляр HashMap
private transient HashMap<E, Object> map;
// Специальный константный объект, используемый в качестве значения для всех ключей
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT) == null;
}
public boolean remove(Object o) {
return map.remove(o) == null;
}
public boolean contains(Object o) {
return map.containsKey(o);
}
// Другие методы...
}
#java #hashset #hashmap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19❤1😁1
public class Quest {
public static void main(String[] args) {
int b = oper2() | oper3() & oper4();
System.out.println("-" + b);
}
private static byte oper2() {
System.out.print(2);
return 2;
}
private static byte oper3() {
System.out.print(3);
return 3;
}
private static byte oper4() {
System.out.print(4);
return 4;
}
}#java #quest
👍2
🎉7
class Person {
Long id;
String name;
public Person(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object obj) {
System.out.print(1);
if (obj == this) {
return true;
}
if (obj instanceof Person person) {
return id.equals(person.id);
}
return false;
}
}
public class Quest {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(1L, "Leo"));
list.add(new Person(2L, "Raph"));
list.add(new Person(3L, "Donnie"));
list.add(new Person(4L, "Mikey"));
list.contains(new Person(3L, "Shredder"));
}
}👍5❤1
🎉2❤1😁1
public class Quest {
public static void main(String[] args) {
byte b = 50;
print(b);
}
private static void print(Short num) {
System.out.println(num++);
}
}👍6
🎉1
Позволяет вставлять новые записи в таблицу или обновлять существующие, если они уже присутствуют. Это удобная операция для предотвращения дублирования данных и упрощения логики обработки записей.
Есть две опции что должно происходить при конфликте при вставке: DO UPDATE и DO NOTHING. Тут все понятно из названия, или обновить запись или ни делать ничего.
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...)
ON CONFLICT (conflict_target)
DO UPDATE SET column1 = value1, column2 = value2, ...;
conflict_target это колонка или набор колонок, которые используются для определения конфликта, обычно это первичный ключ или уникальный индекс. conflict_target можно не указывать и тогда при любом конфликте (дублируется первичный ключ, нарушение уникального индекса и тд.) сработает UPDATE или ничего.
Пример:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE,
email TEXT
);
INSERT INTO users (id, username, email)
VALUES (1, 'user1', 'user1@example.com')
ON CONFLICT
DO NOTHING;
INSERT INTO users (id, username, email)
VALUES (1, 'user1', 'user1@example.com')
ON CONFLICT
DO NOTHING;
Первый INSERT добавит запись, а второй ничего не сделает, так как произойдет дублирование первичного ключа.
#java #PostgreSQL #upsert #update #insert
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥2❤1
public class Quest {
public static void main(String[] args) {
Short b = 50;
inc(b);
System.out.println(b);
}
private static void inc(Short num) {
num++;
}
}👍6🎉3
Этот класс состоит из статических служебных методов для работы с объектами или проверки определенных условий перед операцией.
Класс финальный и создать его не получится, об этом позаботились разработчики:
public final class Objects {
private Objects() {
throw new AssertionError("No java.util.Objects instances for you!");
}
...
}
Метод equals для NPE-безопасного сравнения объектов:
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
Метод toString для NPE-безопасного преобразования объекта в строку:
public static String toString(Object o) {
return String.valueOf(o);
}
Метод toString с дефолтным значением для случая если объект равен null:
public static String toString(Object o, String nullDefault) {
return (o != null) ? o.toString() : nullDefault;
}
Метод requireNonNull позволяет чекнуть объект на null:
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
Забавные методы isNull и nonNull проверяют переменную на null и на не null:
public static boolean isNull(Object obj) {
return obj == null;
}
public static boolean nonNull(Object obj) {
return obj != null;
}
#java #Objects #NPE
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤4🥱2
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❤1
public class Quest {
public static void main(String[] args) {
System.out.println(concat1() < concat2());
}
private static long concat1() {
long start = System.nanoTime();
String s = "";
for (int i = 0; i < 1000; i++) {
s += "-" + i;
}
return System.nanoTime() - start;
}
private static long concat2() {
long start = System.nanoTime();
StringBuilder s = new StringBuilder();
for (int i = 0; i < 1000; i++) {
s.append("-" + i);
}
return System.nanoTime() - start;
}
}#java #quest
👏3
Автоупаковка - это механизм неявной инициализации объектов классов-оберток (
Byte, Short, Integer, Long, Float, Double, Character, Boolean) значениями соответствующих им исходных примитивных типов (byte, short, int...), без явного использования конструктора класса.Автоупаковка происходит при прямом присваивании примитива классу-обертке (с помощью оператора
=), либо при передаче примитива в параметры метода (типа класса-обертки).Автоупаковке в классы-обертки могут быть подвергнуты как переменные примитивных типов, так и константы времени компиляции (литералы и
final-примитивы). При этом литералы должны быть синтаксически корректными для инициализации переменной исходного примитивного типа.Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива типу класса-обертки. Например, попытка упаковать переменную типа
byte в Short, без предварительного явного приведения byte в short вызовет ошибку компиляции.Автоупаковка констант примитивных типов допускает более широкие границы соответствия. В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов:
✔️ неявное расширение/сужение исходного типа примитива до типа примитива, соответствующего классу-обертке (для преобразования
int в Byte, сначала компилятор самостоятельно неявно сужает int к byte)✔️ автоупаковку примитива в соответствующий класс-обертку. Однако, в этом случае существуют два дополнительных ограничения:
a) присвоение примитива обертке может производится только оператором
= (нельзя передать такой примитив в параметры метода без явного приведения типов) b) тип левого операнда не должен быть старше чем
Character, тип правого не должен старше, чем int: допустимо расширение/сужение byte в/из short, byte в/из char, short в/из char и только сужение byte из int, short из int, char из int. Все остальные варианты требуют явного приведения типов).Дополнительной особенностью целочисленных классов-оберток, созданных автоупаковкой констант в диапазоне -128 ... +127 является то, что они кэшируются JVM. Поэтому такие обертки с одинаковыми значениями будут являться ссылками на один объект.
#java #autoboxing
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8