Найти тему

Переход с Java на Kotlin

Оглавление

1. Общий обзор

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

Здесь мы рассмотрим основные примеры переноса нашего Java-кода на Kotlin, такие как простые инструкции print, определение переменных, управление возможностью обнуления.

Затем мы перейдем к внутренним областям, таким как управляющие инструкции, такие как инструкции if-else и switch.

Наконец, мы переходим к определению классов и работе с коллекциями.

2. Основные миграции

Давайте начнем с простых примеров того, как переносить простые инструкции.

2.1. Распечатка выписок

Для начала давайте посмотрим, как работает печать. На Java:

System.out.print("Hello, Baeldung!");
System.out.println("Hello, Baeldung!");

В Котлине:

print("Hello, Baeldung!")
println("Hello, Baeldung!")

2.2. Определение переменных

На Java:

final int a;
final int b = 21;
int c;
int d = 25;
d = 23;
c = 21;

В Котлине:

val a: Int
val b = 21
var c: Int
var d = 25
d = 23
c = 21

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

Всякий раз, когда мы хотим создать конечную переменную, мы можем просто использовать “val” вместо “var”.

2.3. Кастинг

В Java нам нужно выполнять ненужное приведение в действие в таких ситуациях, как:

if(str instanceof String){
String result = ((String) str).substring(1);
}

В Kotlin интеллектуальное приведение позволяет нам пропускать избыточное приведение:

if (str is String) {
val result = str.substring(1)
}

2.4. Битовые операции

Битовые операции в Kotlin гораздо более интуитивно понятны.

Давайте посмотрим на это в действии, на примере Java:

int orResult = a | b;
int andResult = a & b;
int xorResult = a ^ b;
int rightShift = a >> 2;
int leftShift = a << 2;

И в Котлине:

var orResult = a or b
var andResult = a and b
var xorResult = a xor b
var rightShift = a shr 2
var leftShift = a shl 2

3. Нулевая безопасность

На Java:

final String name = null;

String text;
text = null;

if(text != null){
int length = text.length();
}

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

В Kotlin это не так:

val name: String? = null

var lastName: String?
lastName = null

var firstName: String
firstName = null // Compilation error!!

По умолчанию Kotlin предполагает, что значения не могут быть null.

Мы не можем присвоить null имени ссылки, и если мы попытаемся это сделать, это приведет к ошибке компилятора. Если мы хотим создать ссылку с возможностью обнуления, нам нужно добавить знак вопроса(?) к определению типа, как мы это сделали в первой строке.

4. Операции со строками

Строки работают так же, как и в Java. Мы также можем выполнять аналогичные операции, такие как добавление и получение части строки.

В Java:

String name = "John";
String lastName = "Smith";
String text = "My name is: " + name + " " + lastName;
String otherText = "My name is: " + name.substring(2);

String text = "First Line\n" +
"Second Line\n" +
"Third Line";

В Котлине:

val name = "John"
val lastName = "Smith"
val text = "My name is: $name $lastName"
val otherText = "My name is: ${name.substring(2)}"

val text = """
First Line
Second Line
Third Line
""".trimMargin()

Это выглядело довольно просто:

  • Мы можем интерполировать строки, используя символ “$”, и выражения будут вычислены во время выполнения. В Java мы могли бы добиться чего-то подобного, используя String.format()
  • Нет необходимости разбивать многострочные строки, как в Java. Kotlin поддерживает их "из коробки". Нам просто нужно помнить об использовании тройных кавычек

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

val text = "This " + "is " + "a " +
"long " + "long " + "line"

Однако, если первая строка инструкции является допустимой, это не сработает:

val text = "This " + "is " + "a "
+ "long " + "long " + "line" // syntax error

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

val text = ("This " + "is " + "a "
+ "long " + "long " + "line") // no syntax error

5. Циклы и управляющие инструкции

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

5.1. Для цикла

В Java у нас есть различные виды циклов для итерации по коллекции или карте, например:

for (int i = 1; i < 11 ; i++) { }

for (int i = 1; i < 11 ; i+=2) { }

for (String item : collection) { }

for (Map.Entry<String, String> entry: map.entrySet()) { }

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

for (i in 1 until 11) { }

for (i in 1..10 step 2) { }

for (item in collection) { }
for ((index, item) in collection.withIndex()) { }

for ((key, value) in map) { }

5.2. Switch и When

Мы можем использовать операторы switch в Java для принятия выборочных решений:

final int x = ...; // some value
final String xResult;

switch (x) {
case 0:
case 11:
xResult = "0 or 11";
break;
case 1:
case 2:
//...
case 10:
xResult = "from 1 to 10";
break;
default:
if(x < 12 || x > 14) {
xResult = "not from 12 to 14";
break;
}

if(isOdd(x)) {
xResult = "is odd";
break;
}

xResult = "otherwise";
}

final int y = ...; // some value;
final String yResult;

if(isNegative(y)){
yResult = "is Negative";
} else if(isZero(y)){
yResult = "is Zero";
} else if(isOdd(y)){
yResult = "is Odd";
} else {
yResult = "otherwise";
}

В Kotlin вместо оператора switch мы используем оператор when для принятия выборочных решений:

val x = ... // some value
val xResult = when (x) {
0, 11 -> "0 or 11"
in 1..10 -> "from 1 to 10"
!in 12..14 -> "not from 12 to 14"
else -> if (isOdd(x)) { "is odd" } else { "otherwise" }
}

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

val y = ... // some value
val yResult = when {
isNegative(y) -> "is Negative"
isZero(y) -> "is Zero"
isOdd(y) -> "is odd"
else -> "otherwise"
}

6. Занятия

В Java мы определяем класс model и сопровождаем его стандартными установщиками и получателями:

package c
om.baeldung;

public class Person {

private long id;
private String name;
private String brand;
private long price;

// setters and getters
}

В Kotlin получатели и установщики генерируются автоматически:

package com.baeldung

class Person {
var id: Long = 0
var name: String? = null
var brand: String? = null
var price: Long = 0
}

Также можно изменить параметры видимости получателя/установщика, но имейте в виду, что видимость получателя должна совпадать с видимостью свойства.

В Kotlin каждый класс поставляется со следующими методами (которые могут быть переопределены):

  • toString (читаемое строковое представление объекта)
  • hashCode (предоставляет уникальный идентификатор для объекта)
  • equals (используется для сравнения двух объектов из одного класса, чтобы определить, являются ли они одинаковыми)

7. Коллекции

Что ж, мы знаем, что коллекции - это мощная концепция для любого языка программирования; проще говоря, мы можем собирать объекты похожего типа и выполнять операции с ними. Давайте взглянем на них в Java:

final List<Integer> numbers = Arrays.asList(1, 2, 3);

final Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");

// Java 9
final List<Integer> numbers = List.of(1, 2, 3);

final Map<Integer, String> map = Map.of(
1, "One",
2, "Two",
3, "Three");

Теперь в Kotlin у нас могут быть похожие коллекции:

val numbers = listOf(1, 2, 3)

val map = mapOf(
1 to "One",
2 to "Two",
3 to "Three")

Выполнение операций также интересно, как и в Java:

for (int number : numbers) {
System.out.println(number);
}

for (int number : numbers) {
if(number > 5) {
System.out.println(number);
}
}

Далее, мы можем выполнить те же операции в Kotlin гораздо более простым способом:

numbers.forEach {
println(it)
}

numbers
.filter { it > 5 }
.forEach { println(it) }

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

final Map<String, List<Integer>> groups = new HashMap<>();
for (int number : numbers) {
if((number & 1) == 0) {
if(!groups.containsKey("even")) {
groups.put("even", new ArrayList<>());
}

groups.get("even").add(number);
continue;
}

if(!groups.containsKey("odd")){
groups.put("odd", new ArrayList<>());
}

groups.get("odd").add(number);
}

В Котлине:

val groups = numbers.groupBy {
if (it and 1 == 0) "even" else "odd"
}

8. Заключение

Эта статья служит начальной справкой при переходе с Java на Kotlin.

Оригинал статьи: https://www.baeldung.com/kotlin/java-to-kotlin