Telegram Web Link
🖥 Полезный туториал по работе с JSON и не только в Java

Подробно описано использование библиотеки Gson, много полезных примеров.
Например, вот так мы можем сформировать свой JSON:
Gson gson = new Gson();
SmartPhone galaxy8 = new Smartphone("Samsung", "Galaxy 8", 829);
String JSON = gson.toJson(galaxy8);

// {"brand":"Samsung","model":"Galaxy 8","price":829.0}


А вот мы конвертируем JSON-строку в объект Java:
Gson gson = new Gson();
String json = "{\"brand\":\"Samsung\",\"model\":\"Galaxy 8\",\"price\":829.0}";
SmartPhone galxy8 = gson.fromJson(json, SmartPhone.class)

// SmartPhone [brand=Samsung, model=Galaxy 8, price=829.0]


В целом, туториал очень полезный, даёт представление о библиотеке Gson и о том, как обрабатывать JSON в Java

📎 Ссылка

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
💻 Хорошо разбираешься в Kotlin? Готов по полочкам разложить, чем он отличается от Java? Проверь свои знания на этих 10 вопросах

Что из этого в настоящее время не поддерживается в Kotlin?
[x] JVM
[x] JavaScript
[x] LLVM
[_] .NET CLR

Какое выражение Kotlin эквивалентно такому int x = a ? b : c из Java?
[x] val x = a ?: b, c
[x] val x = if (a) b : c
[x] val x = a ? b : c
[_] val x = if (a) b else c

Что применимо для следующего объявления класса?
class Person (val name: String)
[x] Он package-private
[x] Он может быть расширен другими классами
[_] Он public
[x] У него приватное свойство "name"

Есть ли у Kotlin примитивные типы данных, такие как int, long, float?
[x] Нет, Kotlin не имеет и не использует примитивные типы данных.
[_] Нет, не на уровне языка. Но компилятор Kotlin использует примитивы JVM для лучшей производительности.
[x] Да, но Kotlin всегда конвертирует их в не примитивные аналоги.
[x] Да, Kotlin в этом отношении похож на Java.

Что такое to в этом ниже примере:
val test = 33 to 42
[_] Инфиксная функция, создающая пару (33, 42)
[x] Ключевое слово Kotlin для создания пары (33, 42)
[x] Ключевое слово для создания диапазона от 33 до 42
[x] Опечатка

Какое из объявлений функций является валидным?
[x] int sum(int a, int b)
[x] int sum(a: Int, b: Int)
[x] function sum(a: Int, b: Int): Int
[_] fun sum(a: Int, b: Int): Int

В чем ключевое отличие Iterable<T> и Sequence<T> в Kotlin?
[x] Iterable<T> работает только с immutable коллекциями, Sequence<T> применим к mutable
[x] Нет никакой разницы, т. к. Sequence<T> аналог Iterable<T>
[_] Последовательности обрабатываются лениво, итераторы жадно
[x] Последовательности обрабатываются по очереди, итераторы параллельно (многопоточно)

Чего не предлагает dataclass?
[x] Авто-генерируемый метод toString()
[x] Метод copy(...), для создания копии экземпляров.
[_] Автоматическое преобразование из/в JSON
[x] Авто-генерируемые методы hashCode() и equals()

Что выведет следующий код?
     
val listA = mutableListOf(1, 2, 3)
val listB = listA.add(4)
print(listB)

[x] [1, 2, 3, 4]
[_] True
[x] Ничего, тут ошибка компиляции
[x] Unit

В чем разница между a и b?
        
var a: String? = "KotlinQuiz"
var b: String = "KotlinQuiz"

[x] a является volatile, как в Java
[x] b является final и не может быть изменено
[x] a является final и не может быть изменено
[_] b никогда не сможет стать null

Ну как? 10 из 10?

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Для чего нужны функциональные интерфейсы в Java?

Зачем нужны функциональные интерфейсы, если вместо них можно использовать обычную функцию? Пример на картинке.
Так в чем отличие функции от функционального интерфейса? Когда стоит применять функциональный интерфейс, а когда - функцию?


Во-первых, существует функциональный подход (ФП) к программированию, при котором мы можем оперировать методами (функциями) как переменными.
В Haskell, например, ФП встроен непосредственно, на синтаксическом уровне.
Также в некоторых языках (C и C++) можно использовать ссылки на методы, не те, которые в Java, а настоящие ссылки.

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

Когда мы пишем что-то вроде
(car) -> car.getOwner();

нам кажется, будто мы действительно объявляем функцию на месте и используем ФП. Но на деле для такой записи создаётся анонимный класс, расширяющий целевой интерфейс и реализующий метод в соответствии с тем, что написано после стрелки.

Упомянутая ссылка на метод — это просто способ ещё более коротко и изящно записать лямбда-выражение. Например, строка выше могла бы выглядеть так:
Car::getOwner


Для чего всё это нужно? Например, есть у нас список автомобилей, и нам нужно его преобразовать в список владельцев. К примеру, используя Stream API.

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

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

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

📎 Читать подробнее

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Полезная статья про байт-код в Java

Байт-код Java — это промежуточное представление Java-кода, которое выполняется виртуальной машиной Java (JVM). При компиляции Java-программы компилятор Java (javac) преобразует ее в байт-код, представляющий собой набор инструкций, которые JVM может понять и выполнить.
Этот байт-код является платформонезависимым, то есть одна и та же Java-программа может выполняться на различных устройствах и в различных операционных системах, следуя принципу “пиши один раз, выполняй везде” (WORA).

Байт-код представляет собой набор инструкций, которые не являются человекочитаемыми, как Java-код, но менее сложны, чем машинный код.

Длина каждой инструкции в байт-коде Java равна одному байту (откуда и происхождение термина “байт-код”). Однако за некоторыми инструкциями следуют дополнительные байты, представляющие собой операнды для инструкций. Инструкции байт-кода, разработанные для компактности и эффективности, работают на основе стековой архитектуры. В этом их отличие от большинства физических архитектур процессоров, основанных на регистрах.

Поглядим на примере:
int a = 5;
int b = 10;
int sum = a + b;

При компиляции эти строки Java-кода преобразуются в серию инструкций байт-кода, которые при просмотре с помощью такого инструмента, как javap, могут выглядеть следующим образом:
0: iconst_5
1: istore_1
2: bipush 10
4: istore_2
5: iload_1
6: iload_2
7: iadd
8: istore_3


Вообще, тема очень интересная, советую глянуть статью
📎 Статья

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
💻 Анонимные функции в Kotlin

В Kotlin часто используется особый вид функций — анонимные функции. Функции можно не давать имя после ключевого слова fun и она станет анонимной.

val a: (Int) -> Int = fun(i: Int) = i + 3
println(a(4)) // 7

Эта анонимная функция прибавляет к заданному значению число 3.

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

В стандартной библиотеке есть функция count() для подсчёта числа символов в строке.
val charNumber = "Васька".count()
println(charNumber) // выводит 6


Есть перегруженная версия функции, в которой можно вызвать анонимную функцию в качестве аргумента. Зададим новое правило - подсчитать количество символов а в этом же слове.
val charNumber = "Васька".count({letter -> letter == 'а'})
println(charNumber) // выводит 2

Функция count() использует анонимную функцию, чтобы решить, как считать символы в строке. Она последовательно передаёт анонимной функции символ за символом, и если та вернёт истинное значение для заданного символа, общий счёт нужных символов увеличивается на единицу. Как только будет проверен последний символ, функция count() возвратит итоговое значение.
Это одно из применений анонимных функций, в целом очень полезный инструмент.

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Вышла Java 22

Вышла общедоступная версия Java 22. В этот релиз попало около 2300 закрытых задач и 12 JEP'ов. Release Notes можно посмотреть здесь. Полный список изменений API – здесь.


Java 22 не является LTS-релизом, и у неё будут выходить обновления только полгода (до сентября 2024 года).

Скачать
Читать

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Поговорим про механизм исключений в Java

Непроверяемые исключения. Начнем с проблемы. Далеко не все ошибки можно выявить на этапе компиляции, например обращение к несуществующему индексу в массиве. Подобная ошибка возникнет уже во время работы программы и скорее всего остановит ее выполнение:
int[] items = {1, 2, 3};
System.out.println(items[5]);


Запуск такого кода приведет к выбрасыванию (возбуждению) исключения и прерыванию работы программы. В консоли это будет выглядеть так:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
at io.hexlet.Application.main (Application.java:24)


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

Другая похожая ситуация – это деление на ноль, оно тоже приводит к исключению. Такие исключения являются непроверяемыми.

А вот так может выглядеть выкидывание исключений:
throw new RuntimeException("Сообщение об ошибке");



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

Такое исключение должно быть обработано с помощью конструкции try..catch (как это видно на изображении)

📎 Читать подробнее

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥Deque или Stack в Java — что выбрать?

Deque отличается гибкостью и производительностью, превосходя тем самым Stack. Являясь частью Java Collections Framework, Deque предлагает как механизмы работы LIFO (стек), так и FIFO (очередь), предоставляя разнообразные высокопроизводительные реализации, например ArrayDeque, что выделяет его на фоне устаревшего и предназначенного для однопоточности класса Stack.

ArrayDeque можно использовать в качестве стека:
Deque<Integer> stack = new ArrayDeque<>();

stack.push(1); // добавить элемент — easy
int top = stack.peek(); // Взять верхний элемент легко
int pop = stack.pop(); // ...как и нижний


Короче, выбирайте Deque для надежной и эффективной реализации стека

📎 Более подробную инфу про Deque можно найти тут

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
💻 Ключевые различия между Kotlin и Java 🖥

Полезно понимать ограничения и достоинства инструмента, так что держите:

Kotlin сочетает в себе функции как объектно-ориентированного, так и функционального программирования, тогда как Java ограничивается объектно-ориентированным программированием.

Kotlin позволяет пользователям создавать функции расширения, тогда как Java не предлагает никаких функций расширения.

Kotlin не предлагает неявных преобразований, а Java поддерживает неявные преобразования.

В Котлине нет нулевых переменных или объектов; с другой стороны, переменные или объекты Null являются частью языка Java.

Kotlin не поддерживает статические члены, а Java использует статические члены.

В Kotlin переменные примитивного типа являются объектами, а в Java переменные примитивного типа не являются объектами.

Kotlin поддерживает лямбда-выражения, тогда как Java не поддерживает лямбда-выражения (Лямбда-выражения добавлены в Java 8)

Kotlin не требует каких-либо спецификаций переменных типов данных, тогда как Java требует спецификаций переменных типов данных.

Kotlin не требует каких-либо спецификаций переменных типов данных, но Java требует спецификаций переменных типов данных.

Программы Kotlin не требуют точек с запятой в своей программе, в то время как программа Java требует точку с запятой.

Возможности языковых сценариев позволяют использовать Kotlin непосредственно в сценариях сборки Gradle, тогда как Java не предлагает возможностей языковых сценариев.

@android_its
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 JUnit 5 FormattedSource

Библиотека, которая позволяет вам писать параметризованные тесты #JUnit5 простым и понятным способом.

Просто укажите формат и используйте его для определения ваших тестовых примеров 👇

Github

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Что такое Null Pointer Exception и как его исправить?

▶️Что из себя представляет исключение java.lang.NullPointerException и почему оно может происходить?
Какие методы и средства использовать, чтобы определить причину возникновения этого исключения, приводящего к преждевременному прекращению работы приложения?


Ответ и решение

Когда вы объявляете переменную ссылочного типа, на самом деле вы создаете ссылку на объект данного типа. Рассмотрим следующий код для объявления переменной типа int:
int x;
x = 10;

В этом примере переменная x имеет тип int и Java инициализирует её как 0. Когда вы присвоите переменной значение 10 (вторая строка), это значение сохранится в ячейке памяти, на которую ссылается x.

Но когда вы объявляете ссылочный тип, процесс выглядит иначе. Посмотрим на следующий код:
Integer num;
num = new Integer(10);

В первой строке объявлена переменная num, ее тип не относится к встроенному, следовательно, значением является ссылка (тип этой переменной, Integer, является ссылочным типом). Поскольку вы еще не указали, на что собираетесь ссылаться, Java присвоит переменной значение Null, подразумевая «Я ни на что не ссылаюсь».

Во второй строке, ключевое слово new используется для создания объекта типа Integer. Этот объект имеет адрес в памяти, который присваивается переменной num. Теперь, с помощью переменной num вы можете обратиться к объекту используя оператора разыменования ..

Исключение java.lang.NullPointerException возникает, если вы объявили переменную, но не создали объект, то есть если вы попытаетесь разыменовать num до того, как создали объект, вы получите NullPointerException. В самом простом случае, компилятор обнаружит проблему и сообщит, что
num may not have been initialized
Что говорит: «возможно, переменная num не инициализирована».

Иногда исключение вызвано именно тем, что объект действительно не был создан. К примеру, у вас может быть следующая функция:
public void doSomething(Integer num){
// Работаем с num
}

В этом случае создание объекта (переменная num) лежит на вызывающем коде, то есть вы предполагаете, что он был создан ранее – до вызова метода doSomething. К сожалению, следующий вызов метода вполне возможен:
doSomething(null);

В этом случае значение переменной num будет null. Лучшим способом избежать данного исключения будет проверка на равенство нулю. Как результат, функция doSomething должна быть переписана следующим образом:
public void doSomething(Integer num){
if (num != null) {
// Работаем с num
}
}


Как альтернативный вариант предыдущему примеру вы можете сообщить вызывающему коду, что метод был вызван с неверными параметрами, например, с помощью IllegalArgumentException.
public void doSomething(Integer num){
if (num == null)
throw new IllegalArgumentException("Num не должен быть null");
// Работаем с num
}


@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Синтаксис и применение метода substring() в Java

Повторение — мать учения и основа научного метода, так что приступим)

В Java подстрока (substring) относится к непрерывной последовательности символов внутри данной строки. Она позволяет извлекать сегменты текстовых данных на основе начальных и конечных индексов.

🔜 Синтаксис метода substring()
Метод substring() используется для извлечения подстрок из заданной строки в Java. Он поставляется в 2 версиях:

substring(int BeginIndex) — этот метод извлекает символы из указанного значения BeginIndex до конца строки.

substring(int BeginIndex, int EndIndex) — этот метод извлекает символы от BeginIndex до (но не включая) EndIndex.


🔜 Пример использования substring()
public class SubstringExample {
public static void main(String[] args) {
String originalString = "Java is amazing!";

// Извлекаем подстроку от индекса 5 до конца
String substring1 = originalString.substring(5);
System.out.println("Substring 1: " + substring1);

// Извлекаем подстроку с индексом от 0 до 4 (исключая)
String substring2 = originalString.substring(0, 4);
System.out.println("Substring 2: " + substring2);
}
}

substring1 начинается с индекса 5 ("i") и до конца строки, в результате чего получается "is amazing!"
substring2, начиная с индекса 0 ("J") до (но не включая) индекс 4 ("a"), в результате чего получается "Java"


🔜 Рекомендации по использованию метода substring()

Обеспечьте правильную проверку входных индексов, чтобы избежать исключения IndexOutOfBoundsException.

Грамотно обрабатывайте исключительные случаи (edge cases), такие как пустые строки или недопустимые диапазоны индексов.

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

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

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Итерация по диапазону дат в Java

7️⃣Начиная с Java 7, мы будем использовать класс java.util.Date для хранения значений дат и java.util.Calendar для увеличения от одной даты к другой.

Давайте рассмотрим пример использования простого цикла while вместе с классами java.util.Date и java.util.Calendar :
void iterateBetweenDatesJava7(Date start, Date end) {
Date current = start;

while (current.before(end)) {
processDate(current);

Calendar calendar = Calendar.getInstance();
calendar.setTime(current);
calendar.add(Calendar.DATE, 1);
current = calendar.getTime();
}
}



8️⃣Начиная с Java 8, мы можем использовать новый Java 8 Date API. Это дает нам самообрабатываемые, неизменяемые, плавные и потокобезопасные объекты. Это также позволяет нам писать более чистый код без необходимости использования вспомогательного класса, такого как java.util.Calendar, для увеличения дат.

Давайте воспользуемся LocalDate и методом plusDays(1) для перемещения вперед по диапазону дат:
void iterateBetweenDatesJava8(LocalDate start, LocalDate end) {
for (LocalDate date = start; date.isBefore(end); date = date.plusDays(1)) {
processDate(date);
}
}

Здесь стоит отметить, что хотя Stream API доступен, начиная с Java 8, итерация между двумя датами с использованием Date API в сочетании с Stream API невозможна до Java 9.


9️⃣Java 9 представляет метод dateUntil, который позволяет нам использовать Stream API для итерации от даты начала до даты окончания.

Давайте обновим код нашего примера, чтобы воспользоваться этой функцией:
void iterateBetweenDatesJava9(LocalDate start, LocalDate end) {
start.datesUntil(end).forEach(this::processDate);
}


🖥 Фрагменты кода на GitHub

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Java. Лучшие бесплатные курсы для изучения

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

Видео
Список

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
🖥 Реализация бесконечности в Java: все числовые типы данных

Для обозначения бесконечности в Java используйте константы Double.POSITIVE_INFINITY для положительной бесконечности и Double.NEGATIVE_INFINITY для отрицательной:
double posInf = Double.POSITIVE_INFINITY; // +∞
double negInf = Double.NEGATIVE_INFINITY; // -∞


Еще один подход – получить бесконечность путем деления на ноль:
double posInfCalc = 1.0 / 0.0; // +∞
double negInfCalc = -1.0 / 0.0; // -∞

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


Обработка бесконечностей в Java основывается на стандарте IEEE 754 и следует правилам:
🔘Сложение: Double.POSITIVE_INFINITY + anyPositiveDouble всегда будет равно Double.POSITIVE_INFINITY.
🔘Вычитание: Разность между двумя одинаковыми бесконечностями будет NaN (не число).
🔘Умножение: Умножение Double.POSITIVE_INFINITY на отрицательное число приводит к Double.NEGATIVE_INFINITY и наоборот.
🔘Деление: Деление любого числа на Double.POSITIVE_INFINITY даст ноль.

В зависимости от специфики задачи и требуемой точности можно использовать типы Double или Float.

При проведении операций сравнения с бесконечностями учтите:
🔘Double.POSITIVE_INFINITY всегда больше любого конечного значения, в то время как Double.NEGATIVE_INFINITY всегда меньше.
🔘Проверку на равенство с NaN лучше производить с помощью Double.isNaN(), так как любое равенство с NaN возвращает false.
🔘Double.POSITIVE_INFINITY равно Double.POSITIVE_INFINITY, что также верно и для отрицательной бесконечности.

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

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
💻 Немного о конструкции when в Kotlin

Конструкция when проверяет значение некоторого объекта и в зависимости от его значения выполняет тот или иной код. Конструкция when аналогична конструкции switch в других языках. Формальное определение:

значение1 -> действия1
значение2 -> действия2
...
значениеN -> действияN
}


Если значение объекта равно одному из значений в блоке кода when, то выполняются соответствующие действия, которые идут после оператора -> после соответствующего значения:

fun main() {
val isEnabled = true
when(isEnabled){
false -> println("isEnabled off")
true -> println("isEnabled on")
}
}

Здесь в качестве объекта в конструкцию when передается переменная isEnabled. Далее ее значение по порядку сравнивается со значениями в false и true. В данном случае переменная isEnabled равна true, поэтому будет выполняться код:
println("isEnabled on")



Выражение else

В примере выше isEnabled имела только 2 возможных варианта: true и false. Однако чаще бывают случаи, когда значения в блоке when не покрывают все возможные значения объекта. Дополнительное выражение else позволяет задать действия, которые выполняются, если объект не соответствует ни одному из значений:

val a = 30
when(a){
10 -> println("a = 10")
20 -> println("a = 20")
else -> println("неопределенное значение")
}

То есть в данном случае если переменная a равна 30, поэтому она не соответствует ни одному из значений в блоке when. И соответственно будут выполняться инструкции из выражения else.

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

var a = 10
when(a){
10 -> {
println("a = 10")
a *= 2
}
20 -> {
println("a = 20")
a *= 5
}
else -> { println("неопределенное значение")}
}
println(a)


📎 Читать подробнее

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
2024/10/02 00:23:35
Back to Top
HTML Embed Code: