Migrando do Java para o Kotlin

Migrando do Java para o Kotlin

1. Visão geral

Neste tutorial, vamos dar uma olhada em como podemos migrar de Java paraKotlin. Embora veremos muitos exemplos básicos, este artigo não é uma introdução ao Kotlin. Para um artigo dedicado, você pode começar comthis writeup here.

Aqui, veremos exemplos básicos de migração de nosso código Java para Kotlin, como instruções de impressão simples, definição de variáveis ​​e gerenciamento de nulidade.

Em seguida, iremos para as áreas internas, como instruções de controle como if-else e instruções switch.

Finalmente, estamos passando para definir classes e trabalhar com coleções.

Leitura adicional:

Classes de dados em Kotlin

Um exemplo rápido e prático de uso de classes de dados no Kotlin.

Read more

Modificadores de visibilidade em Kotlin

Descubra os modificadores de visibilidade de Kotlin e veja como eles diferem daqueles encontrados em Java.

Read more

Guia Completo de Segurança Nula em Kotlin

Um guia rápido e prático para os recursos de segurança nulos incorporados na linguagem de programação Kotlin.

Read more

2. Migrações básicas

Vamos começar com exemplos simples de como migrar instruções simples.

2.1. Imprimir declarações

Para começar, vamos ver como funciona a impressão. Em Java:

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

Em Kotlin:

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

2.2. Definindo variáveis

Em Java:

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

Em Kotlin:

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

Como podemos ver, o ponto-e-vírgula no Kotlin é opcional. O Kotlin também utiliza inferência de tipo aprimorada e não precisamos definir tipos explicitamente.

Sempre que quisermos criar uma variável final, podemos simplesmente usar“val” em vez de“var”.

2.3. Fundição

Em Java, precisamos executar a conversão desnecessária em situações como:

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

No Kotlin, a transmissão inteligente nos permite pular uma transmissão redundante:

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

2.4. Operações de bit

As operações de bits no Kotlin são muito mais intuitivas.

Vamos ver isso em ação, com o Java:

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

E em Kotlin:

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. Null-Safety

Em Java:

final String name = null;

String text;
text = null;

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

Portanto, não há restrição em Java para atribuir null a variáveis ​​e usá-las. Ao usar qualquer variável, geralmente somos forçados a fazer uma verificação nula também.

Este não é o caso do Kotlin:

val name: String? = null

var lastName: String?
lastName = null

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

Por padrão, Kotlin assume que os valores não podem sernull.

Não podemos atribuirnull à referênciafirstName, e se tentarmos, isso causará um erro do compilador. Se queremos criar uma referência nula, precisamos anexar o ponto de interrogação (?) À definição do tipo, como fizemos na primeira linha.

Mais sobre isso pode ser encontrado emthis article.

4. Operações de String

Strings funciona da mesma maneira que em Java. Podemos fazer operações semelhantes comoappende obter uma parte deString também.

Em 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";

Em Kotlin:

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

Isso parecia bem fácil:

  • Podemos interpolarStrings usando o caractere“$”, e as expressões serão avaliadas em tempo de execução. Em Java, poderíamos conseguir algo semelhante usandoString.format()

  • Não há necessidade de quebrar seqüências de linhas múltiplas como em Java. O Kotlin oferece suporte imediato a eles. Só precisamos lembrar de usar aspas triplas

Não há símbolo para continuação de linha no Kotlin. Como sua gramática permite ter espaços entre quase todos os símbolos, podemos simplesmente quebrar a declaração:

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

No entanto, se a primeira linha da declaração for uma declaração válida, não funcionará:

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

Para evitar esses problemas ao quebrar declarações longas em várias linhas, podemos usar parênteses:

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

5. Loops e declarações de controle

Assim como qualquer outra linguagem de programação, também em Kotlin temos instruções de controle e loops para tarefas repetitivas.

5.1. For Loop

Em Java, temos vários tipos de loops para iterar em uma coleção ou umMap, como:

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

Em Kotlin, temos algo semelhante, mas mais simples. Como já estamos familiarizados, a sintaxe de Kotlin tenta imitar a linguagem natural o máximo possível:

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 eWhen

Podemos usar instruçõesswitch em Java para tomar decisões seletivas:

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";
}

Em Kotlin, em vez de uma declaraçãoswitch, usamos uma declaraçãowhen para tomar decisões seletivas:

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

A declaraçãowhen pode atuar como uma expressão ou uma declaração, com ou sem um argumento:

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

6. Aulas

Em Java, definimos uma classe de modelo e as acompanhamos com setters e getters padrão:

package com.example;

public class Person {

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

    // setters and getters
}

No Kotlin, getters e setters são gerados automaticamente:

package com.example

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

A modificação da visibilidade do getter / setter também pode ser alterada, mas tenha em mente que a visibilidade do getter deve ser igual à visibilidade da propriedade.

No Kotlin, todas as classes vêm com os seguintes métodos (podem ser substituídos):

  • toString (representação de string legível para um objeto)

  • hashCode (fornece um identificador exclusivo para um objeto)

  • equals (usado para comparar dois objetos da mesma classe para ver se eles são iguais)

7. Colecções

Bem, sabemos que Coleções é um conceito poderoso com qualquer linguagem de programação; Simplificando, podemos coletar objetos semelhantes e executar operações com eles. Vamos dar uma olhada naqueles em 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");

Agora, no Kotlin, podemos ter coleções semelhantes:

val numbers = listOf(1, 2, 3)

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

A execução de operações também é interessante, como em Java:

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

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

Em seguida, podemos executar as mesmas operações no Kotlin de uma maneira muito mais simples:

numbers.forEach {
    println(it)
}

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

Vamos estudar um exemplo final sobre a coleta de números pares e ímpares emMap deString como chaves eList deIntegers como seus valores. Em Java, teremos que escrever:

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

Em Kotlin:

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

8. Conclusão

Este artigo serve como ajuda inicial ao passar do Java para o Kotlin.

Embora a comparação tenha sido apenas uma dica de como o Kotlin pode ser simples e intuitivo, outros artigoscan be found here.