Миграция с Java на Котлин

Миграция с Явы в Котлин

1. обзор

В этом руководстве мы рассмотрим, как перейти с Java наKotlin. Хотя мы рассмотрим множество основных примеров, эта статья не является введением в Kotlin. Для отдельной статьи вы можете начать сthis writeup here.

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

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

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

Дальнейшее чтение:

Классы данных в Котлине

Быстрый и практический пример использования классов данных в Kotlin.

Read more

Модификаторы видимости в Котлине

Откройте для себя модификаторы видимости Kotlin и посмотрите, чем они отличаются от модификаторов Java.

Read more

Всеобъемлющее руководство по нулевой безопасности в Котлине

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

Read more

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

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

2.1. Печатать заявления

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

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

В Котлине:

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

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 и их использование. При использовании любой переменной мы обычно также вынуждены делать нулевую проверку.

Это не тот случай с Kotlin:

val name: String? = null

var lastName: String?
lastName = null

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

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

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

Подробнее об этом можно прочитать вthis article.

4. Строковые Операции

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

В 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()

Это выглядело довольно легко:

  • Мы можем интерполироватьStrings с помощью символа“$”, и выражения будут оцениваться во время выполнения. В Java мы могли бы добиться чего-то подобного, используяString.format()

  • Нет необходимости ломать многострочные строки, как в Java. 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 у нас есть различные типы циклов для перебора коллекции илиMap,, например:

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

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

for (String item : collection) { }

for (Map.Entry 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 мы определяем класс модели и сопровождаем их стандартными установщиками и получателями:

package com.example;

public class Person {

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

    // setters and getters
}

В Котлине геттеры и сеттеры генерируются автоматически:

package com.example

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 numbers = Arrays.asList(1, 2, 3);

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

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

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

Теперь в Котлине мы можем иметь похожие коллекции:

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) }

Давайте рассмотрим последний пример сбора четных и нечетных чисел вMap изString в качестве ключей иList изIntegers в качестве их значения. На Java нам нужно будет написать:

final Map> 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.

Хотя сравнение было лишь намеком на то, насколько простым и интуитивно понятным может быть Kotlin, другие статьиcan be found here.