Подробно описано использование библиотеки Gson, много полезных примеров.
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}
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
int x = a ? b : c
из Java?val x = a ?: b, c
val x = if (a) b : c
val x = a ? b : c
val x = if (a) b else c
class Person (val name: String)
int
, long
, float
?to
в этом ниже примере:val test = 33 to 42
int sum(int a, int b)
int sum(a: Int, b: Int)
function sum(a: Int, b: Int): Int
fun sum(a: Int, b: Int): Int
Iterable<T>
и Sequence<T>
в Kotlin?Iterable<T>
работает только с immutable
коллекциями, Sequence<T>
применим к mutable
Sequence<T>
аналог Iterable<T>
dataclass
?toString()
copy(...)
, для создания копии экземпляров.hashCode()
и equals()
val listA = mutableListOf(1, 2, 3)
val listB = listA.add(4)
print(listB)
[1, 2, 3, 4]
True
Unit
a
и b
?
var a: String? = "KotlinQuiz"
var b: String = "KotlinQuiz"
a
является volatile
, как в Javab
является final
и не может быть измененоa
является final
и не может быть измененоb
никогда не сможет стать null
Ну как? 10 из 10?
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Так в чем отличие функции от функционального интерфейса? Когда стоит применять функциональный интерфейс, а когда - функцию?
В 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
javac
) преобразует ее в байт-код, представляющий собой набор инструкций, которые JVM может понять и выполнить. Этот байт-код является платформонезависимым, то есть одна и та же Java-программа может выполняться на различных устройствах и в различных операционных системах, следуя принципу “пиши один раз, выполняй везде” (WORA).
Поглядим на примере:
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 часто используется особый вид функций — анонимные функции. Функции можно не давать имя после ключевого слова
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. В этот релиз попало около 2300 закрытых задач и 12 JEP'ов. Release Notes можно посмотреть здесь. Полный список изменений API – здесь.
Java 22 не является LTS-релизом, и у неё будут выходить обновления только полгода (до сентября 2024 года).
▪Скачать
▪Читать
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
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 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
Полезно понимать ограничения и достоинства инструмента, так что держите:
Null
являются частью языка Java.@android_its
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
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
Повторение — мать учения и основа научного метода, так что приступим)
В 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
.@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
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();
}
}
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.
dateUntil,
который позволяет нам использовать Stream API для итерации от даты начала до даты окончания.Давайте обновим код нашего примера, чтобы воспользоваться этой функцией:
void iterateBetweenDatesJava9(LocalDate start, LocalDate end) {
start.datesUntil(end).forEach(this::processDate);
}
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
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
проверяет значение некоторого объекта и в зависимости от его значения выполняет тот или иной код. Конструкция 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")
В примере выше
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