Kotlin - Guia rápido

Kotlin é uma nova linguagem de programação de código aberto como Java, JavaScript, etc. É uma linguagem de alto nível fortemente tipada que combina parte funcional e técnica em um mesmo lugar. Atualmente, o Kotlin é voltado para Java e JavaScript. Ele roda em JVM.

Kotlin é influenciado por outras linguagens de programação, como Java, Scala, Groovy, Gosu, etc. A sintaxe de Kotlin pode não ser exatamente semelhante a JAVA, no entanto, internamente Kotlin depende da biblioteca de classes Java existente para produzir resultados maravilhosos para os programadores . Kotlin oferece interoperabilidade, segurança de código e clareza para os desenvolvedores em todo o mundo.

Vantagens e desvantagens

A seguir estão algumas das vantagens de usar Kotlin para o desenvolvimento de seu aplicativo.

Easy Language- Kotlin é uma linguagem funcional e muito fácil de aprender. A sintaxe é muito semelhante a Java, portanto, é muito fácil de lembrar. Kotlin é mais expressivo, o que torna seu código mais legível e compreensível.

Concise- Kotlin é baseado em JVM e é uma linguagem funcional. Assim, ele reduz muito código clichê usado em outras linguagens de programação.

Runtime and Performance - Melhor desempenho e menor tempo de execução.

Interoperability - Kotlin está maduro o suficiente para construir um aplicativo interoperável de uma maneira menos complexa.

Brand New- Kotlin é uma nova linguagem que oferece aos desenvolvedores um novo começo. Não é uma substituição do Java, embora seja desenvolvido sobre JVM. É aceita como a primeira língua oficial de desenvolvimento do Android. Kotlin pode ser definido como - Kotlin = JAVA + novos recursos extras atualizados.

A seguir estão algumas das desvantagens do Kotlin.

Namespace declaration- Kotlin permite que os desenvolvedores declarem as funções no nível superior. No entanto, sempre que a mesma função é declarada em muitos lugares de seu aplicativo, é difícil entender qual função está sendo chamada.

No Static Declaration - Kotlin não tem um modificador de manipulação estática usual como Java, o que pode causar alguns problemas para o desenvolvedor Java convencional.

No entanto, se você ainda quiser usar o Kotlin offline em seu sistema local, será necessário executar as etapas a seguir para configurar seu espaço de trabalho local.

Step 1 - Instalação do Java 8.

O Kotlin é executado em JVM, portanto. é realmente necessário usar o JDK 8 para o desenvolvimento local do Kotlin. Consulte o site oficial da oracle para baixar e instalar o JDK 8 ou uma versão superior. Pode ser necessário definir a variável de ambiente para JAVA para que ele funcione corretamente. Para verificar sua instalação no sistema operacional Windows, clique em “java –version” no prompt de comando e como resultado será exibida a versão java instalada em seu sistema.

Step 2 - Instalação IDE.

Existem vários IDE disponíveis na Internet. Você pode usar qualquer um de sua escolha. Você pode encontrar o link de download de diferentes IDE na tabela a seguir.

Nome IDE Link de instalação
NetBeans https://netbeans.org/downloads/
Eclipse https://www.eclipse.org/downloads/
Intellij https://www.jetbrains.com/idea/download/#section = windows

É sempre recomendável usar a versão recente do software para extrair o máximo de facilidade dela.

Step 3 - Configurando Eclipse.

Abra o Eclipse e vá para “Eclipse Market Place”. Você encontrará a seguinte tela.

Procure Kotlin na caixa de pesquisa e instale o mesmo em seu sistema local. Pode levar algum tempo dependendo da velocidade da Internet. Pode ser necessário reiniciar o Eclipse, depois que ele for instalado com sucesso.

Step 4 - Projeto Kotlin.

Depois que o Eclipse for reiniciado com sucesso e o Kotlin instalado, você poderá criar um projeto Kotlin rapidamente. Vamos paraFile → New → Others e selecione “Projeto Kotlin” na lista.

Assim que a configuração do projeto for concluída, você pode criar um arquivo Kotlin na pasta “SRC”. Clique com o botão esquerdo na pasta “Src” e selecione “novo”. Você terá uma opção para o arquivo Kotlin, caso contrário, pode ser necessário pesquisar nos “outros”. Assim que o novo arquivo for criado, o diretório do seu projeto terá a seguinte aparência.

Seu ambiente de desenvolvimento está pronto agora. Vá em frente e adicione o seguinte trecho de código no arquivo “Hello.kt”.

fun main(args: Array<String>) {
   println("Hello, World!")
}

Execute-o como um aplicativo Kotlin e veja a saída no console, conforme mostrado na captura de tela a seguir. Para melhor compreensão e disponibilidade, usaremos nossa ferramenta de base de codificação.

Hello, World!

Kotlin é uma linguagem de programação e possui sua própria arquitetura para alocar memória e produzir uma saída de qualidade para o usuário final. A seguir estão os diferentes cenários em que o compilador Kotlin funcionará de maneira diferente, sempre que for direcionado a outros tipos de linguagens diferentes, como Java e JavaScript.

O compilador Kotlin cria um código de byte e esse código de byte pode ser executado na JVM, que é exatamente igual ao código de byte gerado pelo Java .classArquivo. Sempre que um arquivo com código de dois bytes é executado na JVM, eles podem se comunicar entre si e é assim que um recurso interoperável é estabelecido no Kotlin para Java.

Sempre que Kotlin visa JavaScript, o compilador Kotlin converte o .ktarquivo em ES5.1 e gera um código compatível para JavaScript. O compilador Kotlin é capaz de criar códigos compatíveis com a plataforma via LLVM.

Neste capítulo, aprenderemos sobre os tipos de dados básicos disponíveis na linguagem de programação Kotlin.

Números

A representação de números em Kotlin é muito semelhante a Java, no entanto, Kotlin não permite a conversão interna de diferentes tipos de dados. A tabela a seguir lista diferentes comprimentos de variáveis ​​para diferentes números.

Tipo Tamanho
em dobro 64
Flutuador 32
Grandes 64
Int 32
Baixo 16
Byte 8

No exemplo a seguir, veremos como Kotlin funciona com diferentes tipos de dados. Por favor, insira o seguinte conjunto de código em nosso campo de codificação.

fun main(args: Array<String>) {
   val a: Int = 10000
   val d: Double = 100.00
   val f: Float = 100.00f
   val l: Long = 1000000004
   val s: Short = 10
   val b: Byte = 1
   
   println("Your Int Value is "+a);
   println("Your Double  Value is "+d);
   println("Your Float Value is "+f);
   println("Your Long Value is "+l);
   println("Your Short Value is "+s);
   println("Your Byte Value is "+b);
}

Quando você executa o trecho de código acima no campo de codificação, ele irá gerar a seguinte saída no console da web.

Your Int Value is 10000
Your Double  Value is 100.0
Your Float Value is 100.0
Your Long Value is 1000000004
Your Short Value is 10
Your Byte Value is 1

Personagens

Kotlin representa o personagem usando char. O caractere deve ser declarado em aspas simples, como‘c’. Por favor, insira o seguinte código em nosso campo de codificação e veja como Kotlin interpreta a variável de caractere. Variáveis ​​de caracteres não podem ser declaradas como variáveis ​​numéricas. A variável Kotlin pode ser declarada de duas maneiras - uma usando“var” e outro usando “val”.

fun main(args: Array<String>) {
   val letter: Char    // defining a variable 
   letter = 'A'        // Assigning a value to it 
   println("$letter")
}

O trecho de código acima produzirá a seguinte saída na janela de saída do navegador.

A

boleano

Boolean é muito simples como outras linguagens de programação. Temos apenas dois valores para Boolean - verdadeiro ou falso. No exemplo a seguir, veremos como Kotlin interpreta o booleano.

fun main(args: Array<String>) {
   val letter: Boolean   // defining a variable 
   letter = true         // Assinging a value to it 
   println("Your character value is "+"$letter")
}

O trecho de código acima produzirá a seguinte saída no navegador.

Your character value is true

Cordas

Strings são matrizes de caracteres. Como Java, eles são imutáveis ​​por natureza. Temos dois tipos de string disponíveis em Kotlin - um é chamadoraw String e outro é chamado escaped String. No exemplo a seguir, faremos uso dessas strings.

fun main(args: Array<String>) {
   var rawString :String  = "I am Raw String!"
   val escapedString : String  = "I am escaped String!\n"
   
   println("Hello!"+escapedString)
   println("Hey!!"+rawString)   
}

O exemplo acima de String com escape permite fornecer espaço de linha extra após a primeira instrução de impressão. A seguir será a saída no navegador.

Hello!I am escaped String!

Hey!!I am Raw String!

Arrays

Arrays são uma coleção de dados homogêneos. Como o Java, o Kotlin oferece suporte a matrizes de diferentes tipos de dados. No exemplo a seguir, faremos uso de diferentes arrays.

fun main(args: Array<String>) {
   val numbers: IntArray = intArrayOf(1, 2, 3, 4, 5)
   println("Hey!! I am array Example"+numbers[2])
}

O trecho de código acima produz a seguinte saída. A indexação da matriz é semelhante a outras linguagens de programação. Procuramos aqui um segundo índice, cujo valor é “3”.

Hey!! I am array Example3

Coleções

A coleta é uma parte muito importante da estrutura de dados, o que torna o desenvolvimento de software fácil para os engenheiros. Kotlin tem dois tipos de coleção - um éimmutable collection (o que significa listas, mapas e conjuntos que não podem ser editáveis) e outro é mutable collection(este tipo de coleção é editável). É muito importante ter em mente o tipo de coleção usada em sua aplicação, pois o sistema Kotlin não representa nenhuma diferença específica entre elas.

fun main(args: Array<String>) { 
   val numbers: MutableList<Int> = mutableListOf(1, 2, 3) //mutable List 
   val readOnlyView: List<Int> = numbers                  // immutable list 
   println("my mutable list--"+numbers)        // prints "[1, 2, 3]" 
   numbers.add(4) 
   println("my mutable list after addition --"+numbers)        // prints "[1, 2, 3, 4]" 
   println(readOnlyView)     
   readOnlyView.clear()    // ⇒ does not compile  
// gives error  
}

O trecho de código acima produzirá a seguinte saída no navegador. Ele dá um erro quando tentamos limpar a lista mutável da coleção.

main.kt:9:18: error: unresolved reference: clear
   readOnlyView.clear()    // -> does not compile  
                 ^

Na coleção, Kotlin fornece alguns métodos úteis, como first(), last(), filter(), etc. Todos esses métodos são autodescritivos e fáceis de implementar. Além disso, o Kotlin segue a mesma estrutura do Java ao implementar a coleção. Você é livre para implementar qualquer coleção de sua escolha, como Mapear e Definir.

No exemplo a seguir, implementamos Map e Set usando diferentes métodos integrados.

fun main(args: Array<String>) {
   val items = listOf(1, 2, 3, 4)
   println("First Element of our list----"+items.first())
   println("Last Element of our list----"+items.last())
   println("Even Numbers of our List----"+items.
      filter { it % 2 = = 0 })   // returns [2, 4]
   
   val readWriteMap = hashMapOf("foo" to 1, "bar" to 2)
   println(readWriteMap["foo"])  // prints "1"
   
   val strings = hashSetOf("a", "b", "c", "c")
   println("My Set Values are"+strings)
}

O trecho de código acima produz a seguinte saída no navegador.

First Element of our list----1
Last Element of our list----4
Even Numbers of our List----[2, 4]
1
My Set Values are[a, b, c]

Gamas

Ranges é outra característica única de Kotlin. Como Haskell, ele fornece um operador que o ajuda a iterar em um intervalo. Internamente, é implementado usandorangeTo() e sua forma de operador é (..).

No exemplo a seguir, veremos como Kotlin interpreta esse operador de intervalo.

fun main(args: Array<String>) {
   val i:Int  = 2
   for (j in 1..4) 
   print(j) // prints "1234"
   
   if (i in 1..10) { // equivalent of 1 < = i && i < = 10
      println("we found your number --"+i)
   }
}

O trecho de código acima produz a seguinte saída no navegador.

1234we found your number --2

No capítulo anterior, aprendemos sobre os diferentes tipos de tipos de dados disponíveis no sistema Kotlin. Neste capítulo, discutiremos os diferentes tipos de mecanismo de fluxo de controle disponíveis no Kotlin.

If - Else

Kotlin é uma linguagem funcional, portanto, como toda linguagem funcional em Kotlin “if”é uma expressão, não é uma palavra-chave. A expressão“if”retornará um valor sempre que necessário. Como outras linguagens de programação,“if-else”bloco é usado como um operador de verificação condicional inicial. No exemplo a seguir, compararemos duas variáveis ​​e forneceremos a saída necessária de acordo.

fun main(args: Array<String>) {
   val a:Int = 5
   val b:Int = 2
   var max: Int
   
   if (a > b) {
      max = a
   } else {
      max = b
   }
   print("Maximum of a or b is " +max)
 
   // As expression 
   // val max = if (a > b) a else b
}

O trecho de código acima produz a seguinte saída como resultado no navegador. Nosso exemplo também contém outra linha de código, que descreve como usar“If” declaração como uma expressão.

Maximum of a or b is 5

Uso de quando

Se você está familiarizado com outras linguagens de programação, então deve ter ouvido falar do termo switch statement, que é basicamente um operador condicional quando várias condições podem ser aplicadas a uma determinada variável. “when”operador compara o valor da variável com as condições do ramo. Se estiver satisfazendo a condição de ramificação, ele executará a instrução dentro desse escopo. No exemplo a seguir, aprenderemos mais sobre “quando” em Kotlin.

fun main(args: Array<String>) {
   val x:Int = 5
   when (x) {
      1 -> print("x = = 1")
      2 -> print("x = = 2")
      
      else -> { // Note the block
         print("x is neither 1 nor 2")
      }
   }
}

O trecho de código acima produz a seguinte saída no navegador.

x is neither 1 nor 2

No exemplo acima, o compilador Kotlin corresponde ao valor de xcom os ramos fornecidos. Se não corresponder a nenhum dos ramos, ele executará a outra parte. Praticamente, quando é equivalente a um bloco if múltiplo. Kotlin oferece outra flexibilidade para o desenvolvedor, onde o desenvolvedor pode fornecer várias verificações na mesma linha, fornecendo “,” dentro das verificações. Vamos modificar o exemplo acima como segue.

fun main(args: Array<String>) {
   val x:Int = 5
   when (x) {
      1,2 -> print(" Value of X either 1,2")
      
      else -> { // Note the block
         print("x is neither 1 nor 2")
      }
   }
}

Execute o mesmo no navegador, o que produzirá a seguinte saída no navegador.

x is neither 1 nor 2

For Loop

Loop é uma invenção que fornece a flexibilidade de iterar por meio de qualquer tipo de estrutura de dados. Como outras linguagens de programação, Kotlin também oferece muitos tipos de metodologia de Looping, no entanto, entre eles“For”é o mais bem sucedido. A implementação e o uso do loop For são conceitualmente semelhantes ao loop for Java. O exemplo a seguir mostra como podemos usar o mesmo em exemplos da vida real.

fun main(args: Array<String>) {
   val items = listOf(1, 2, 3, 4)
   for (i in items) println("values of the array"+i)
}

No trecho de código acima, declaramos uma lista nomeada como “itens” e, usando o loop for, estamos iterando por essa lista definida e imprimindo seu valor no navegador. A seguir está a saída.

values of the array1
values of the array2
values of the array3
values of the array4

A seguir está outro exemplo de código, onde estamos usando alguma função de biblioteca para tornar nosso trabalho de desenvolvimento mais fácil do que nunca.

fun main(args: Array<String>) {
   val items = listOf(1, 22, 83, 4)
   
   for ((index, value) in items.withIndex()) {
      println("the element at $index is $value")
   }
}

Assim que compilarmos e executarmos o trecho de código acima em nosso campo de codificação, ele produzirá a seguinte saída no navegador.

the element at 0 is 1
the element at 1 is 22
the element at 2 is 83
the element at 3 is 4

Loop While e Loop Do-While

While e Do-While funcionam exatamente de maneira semelhante como fazem em outras linguagens de programação. A única diferença entre esses dois loops é que, no caso do loop Do-while, a condição será testada no final do loop. O exemplo a seguir mostra o uso doWhile loop.

fun main(args: Array<String>) {
   var x:Int = 0
   println("Example of While Loop--")
   
   while(x< = 10) {
      println(x)
      x++
   } 
}

O trecho de código acima produz a seguinte saída no navegador.

Example of While Loop--
0
1
2
3
4
5
6
7
8
9
10

O Kotlin também tem outro loop chamado loop Do-While, onde o corpo do loop será executado uma vez, somente então a condição será verificada. O exemplo a seguir mostra o uso doDo-while loop.

fun main(args: Array<String>) {
   var x:Int = 0
   do {
      x = x + 10
      println("I am inside Do block---"+x)
   } while(x <= 50)
}

O trecho de código acima produz a seguinte saída no navegador. No código acima, o compilador Kotlin irá executar o bloco DO, então ele irá para a verificação de condição do bloco while.

I am inside Do block---10
I am inside Do block---20
I am inside Do block---30
I am inside Do block---40
I am inside Do block---50
I am inside Do block---60

Uso de Return, Break, Continue

Se você está familiarizado com qualquer linguagem de programação, então deve ter uma ideia de diferentes palavras-chave que nos ajudem a implementar um bom fluxo de controle na aplicação. A seguir estão as diferentes palavras-chave que podem ser usadas para controlar os loops ou qualquer outro tipo de fluxo de controle.

Return- Return é uma palavra-chave que retorna algum valor para a função de chamada da função chamada. No exemplo a seguir, implementaremos esse cenário usando nosso campo de codificação Kotlin.

fun main(args: Array<String>) {
   var x:Int = 10
   println("The value of X is--"+doubleMe(x))
}
fun doubleMe(x:Int):Int {
   return 2*x;
}

No trecho de código acima, estamos chamando outra função e multiplicando a entrada por 2 e retornando o valor resultante para a função chamada que é nossa função principal. Kotlin define a função de uma maneira diferente, que veremos em um capítulo subsequente. Por enquanto, basta entender que o código acima irá gerar a seguinte saída no navegador.

The value of X is--20

Continue & Break- Continuar e interromper são a parte mais vital de um problema lógico. A palavra-chave “break” termina o fluxo do controlador se alguma condição falhou e “continue” faz o oposto. Toda essa operação acontece com visibilidade imediata. Kotlin é mais inteligente do que outras linguagens de programação, em que o desenvolvedor pode aplicar mais de um rótulo como visibilidade. O código a seguir mostra como estamos implementando esse rótulo no Kotlin.

fun main(args: Array<String>) {
   println("Example of Break and Continue")
   myLabel@ for(x in 1..10) { // appling the custom label
      if(x = = 5) {
         println("I am inside if block with value"+x+"\n-- hence it will close the operation")
         break@myLabel //specifing the label
      } else {
         println("I am inside else block with value"+x)
         continue@myLabel
      }
   }
}

O trecho de código acima produz a seguinte saída no navegador.

Example of Break and Continue
I am inside else block with value1
I am inside else block with value2
I am inside else block with value3
I am inside else block with value4
I am inside if block with value5
-- hence it will close the operation

Como você pode ver, o controlador continua o loop, até e a menos que o valor de x é 5. Uma vez que o valor de x chega a 5, ele começa a executar o bloco if e uma vez que a instrução break é alcançada, todo o fluxo de controle termina a execução do programa.

Neste capítulo, aprenderemos os fundamentos da Programação Orientada a Objetos (OOP) usando Kotlin. Aprenderemos sobre a classe e seu objeto e como brincar com esse objeto. Por definição de OOP, uma classe é um projeto de uma entidade de tempo de execução e o objeto é seu estado, que inclui seu comportamento e estado. Em Kotlin, a declaração de classe consiste em um cabeçalho de classe e um corpo de classe cercado por chaves, semelhante a Java.

Class myClass { // class Header 

   // class Body
}

Assim como o Java, o Kotlin também permite criar vários objetos de uma classe e você é livre para incluir seus membros e funções de classe. Podemos controlar a visibilidade das variáveis ​​dos membros da classe usando diferentes palavras-chave que aprenderemos no Capítulo 10 - Controle de visibilidade. No exemplo a seguir, criaremos uma classe e seu objeto por meio do qual acessaremos diferentes membros de dados dessa classe.

class myClass {
   // property (data member)
   private var name: String = "Tutorials.point"
   
   // member function
   fun printMe() {
      print("You are at the best Learning website Named-"+name)
   }
}
fun main(args: Array<String>) {
   val obj = myClass() // create obj object of myClass class
   obj.printMe()
}

O trecho de código acima produzirá a seguinte saída no navegador, onde estamos chamando printMe () de myClass usando seu próprio objeto.

You are at the best Learning website Named- Tutorials.point

Classe Aninhada

Por definição, quando uma classe é criada dentro de outra classe, ela é chamada como uma classe aninhada. No Kotlin, a classe aninhada é estática por padrão, portanto, pode ser acessada sem a criação de nenhum objeto dessa classe. No exemplo a seguir, veremos como Kotlin interpreta nossa classe aninhada.

fun main(args: Array<String>) {
   val demo = Outer.Nested().foo() // calling nested class method
   print(demo)
}
class Outer {
   class Nested {
      fun foo() = "Welcome to The TutorialsPoint.com"
   }
}

O trecho de código acima produzirá a seguinte saída no navegador.

Welcome to The TutorialsPoint.com

Classe Interna

Quando uma classe aninhada é marcada como “interna”, ela será chamada de classe interna. Uma classe interna pode ser acessada pelo membro de dados da classe externa. No exemplo a seguir, estaremos acessando o membro de dados da classe externa.

fun main(args: Array<String>) {
   val demo = Outer().Nested().foo() // calling nested class method
   print(demo)
}
class Outer {
   private val welcomeMessage: String = "Welcome to the TutorialsPoint.com"
   inner class Nested {
      fun foo() = welcomeMessage
   }
}

O trecho de código acima produzirá a seguinte saída no navegador, onde estamos chamando a classe aninhada usando o construtor padrão fornecido pelos compiladores Kotlin no momento da compilação.

Welcome to the TutorialsPoint.com

Classe interna anônima

Classe interna anônima é um conceito muito bom que torna a vida de um programador muito fácil. Sempre que estamos implementando uma interface, o conceito de bloqueio interno anônimo entra em cena. O conceito de criação de um objeto de interface usando referência de objeto em tempo de execução é conhecido como classe anônima. No exemplo a seguir, vamos criar uma interface e vamos criar um objeto dessa interface usando o mecanismo da classe Anonymous Inner.

fun main(args: Array<String>) {
   var programmer :Human = object:Human // creating an instance of the interface {
      override fun think() { // overriding the think method
         print("I am an example of Anonymous Inner Class ")
      }
   }
   programmer.think()
}
interface Human {
   fun think()
}

O trecho de código acima produzirá a seguinte saída no navegador.

I am an example of Anonymous Inner Class

Digite aliases

Os aliases de tipo são propriedade do compilador Kotlin. Ele fornece a flexibilidade de criar um novo nome de um tipo existente, mas não cria um novo tipo. Se o nome do tipo for muito longo, você pode facilmente introduzir um nome mais curto e usar o mesmo para uso futuro. Os aliases de tipo são realmente úteis para tipos complexos. Na versão mais recente, o Kotlin revogou o suporte para aliases de tipo, no entanto, se você estiver usando uma versão antiga do Kotlin, pode ser necessário usá-la da seguinte forma -

typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList<File>>

Neste capítulo, aprenderemos sobre construtores em Kotlin. Kotlin tem dois tipos de construtor - um é oprimary constructor e o outro é o secondary constructor. Uma classe Kotlin pode ter um construtor primário e um ou mais construtores secundários. O construtor Java inicializa as variáveis ​​de membro, no entanto, em Kotlin, o construtor primário inicializa a classe, enquanto o construtor secundário ajuda a incluir alguma lógica extra ao inicializar a mesma. O construtor primário pode ser declarado no nível do cabeçalho da classe, conforme mostrado no exemplo a seguir.

class Person(val firstName: String, var age: Int) {
   // class body
}

No exemplo acima, declaramos o construtor primário entre parênteses. Entre os dois campos, o primeiro nome é somente leitura, pois é declarado como “val”, enquanto o campo idade pode ser editado. No exemplo a seguir, usaremos o construtor primário.

fun main(args: Array<String>) {
   val person1 = Person("TutorialsPoint.com", 15)
   println("First Name = ${person1.firstName}") println("Age = ${person1.age}")
}
class Person(val firstName: String, var age: Int) {
}

O trecho de código acima inicializará automaticamente as duas variáveis ​​e fornecerá a seguinte saída no navegador.

First Name = TutorialsPoint.com
Age = 15

Conforme mencionado anteriormente, o Kotlin permite criar um ou mais construtores secundários para sua classe. Este construtor secundário é criado usando a palavra-chave “construtor”. Ele é necessário sempre que você deseja criar mais de um construtor em Kotlin ou sempre que deseja incluir mais lógica no construtor primário e você não pode fazer isso porque o construtor primário pode ser chamado por alguma outra classe. Dê uma olhada no exemplo a seguir, onde criamos um construtor secundário e estamos usando o exemplo acima para implementar o mesmo.

fun main(args: Array<String>) {
   val HUman = HUman("TutorialsPoint.com", 25)
   print("${HUman.message}"+"${HUman.firstName}"+
      "Welcome to the example of Secondary  constructor, Your Age is-${HUman.age}")
}
class HUman(val firstName: String, var age: Int) {
   val message:String  = "Hey!!!"
	constructor(name : String , age :Int ,message :String):this(name,age) {
   }
}

Note - Qualquer número de construtores secundários pode ser criado, no entanto, todos esses construtores devem chamar o construtor primário direta ou indiretamente.

O trecho de código acima produzirá a seguinte saída no navegador.

Hey!!! TutorialsPoint.comWelcome to the example of Secondary  constructor, Your Age is- 25

Neste capítulo, aprenderemos sobre herança. Por definição, todos nós sabemos que herança significa acumular algumas propriedades da classe mãe na classe filha. No Kotlin, a classe base é nomeada como “Qualquer”, que é a superclasse da classe padrão 'qualquer' declarada no Kotlin. Como todos os outros OOPS, Kotlin também fornece essa funcionalidade usando uma palavra-chave conhecida como“:”.

Tudo no Kotlin é, por padrão, final, portanto, precisamos usar a palavra-chave “abrir” na frente da declaração da classe para permitir a herança. Dê uma olhada no seguinte exemplo de herança.

import java.util.Arrays

open class ABC {
   fun think () {
      print("Hey!! i am thiking ")
   }
}
class BCD: ABC(){ // inheritence happend using default constructor 
}

fun main(args: Array<String>) {
   var  a = BCD()
   a.think()
}

O trecho de código acima produzirá a seguinte saída no navegador.

Hey!! i am thiking

Agora, e se quisermos sobrescrever o método think () na classe filha. Então, precisamos considerar o exemplo a seguir, onde estamos criando duas classes e substituindo uma de suas funções na classe filha.

import java.util.Arrays

open class ABC {
   open fun think () {
      print("Hey!! i am thinking ")
   }
}
class BCD: ABC() { // inheritance happens using default constructor 
   override fun think() {
      print("I Am from Child")
   }
}
fun main(args: Array<String>) {
   var  a = BCD()
   a.think()
}

A parte do código acima chamará o método herdado da classe filha e produzirá a seguinte saída no navegador. Como Java, Kotlin também não permite várias heranças.

I Am from Child

Neste capítulo, aprenderemos sobre a interface em Kotlin. No Kotlin, a interface funciona exatamente de forma semelhante ao Java 8, o que significa que eles podem conter a implementação de métodos, bem como a declaração de métodos abstratos. Uma interface pode ser implementada por uma classe para usar sua funcionalidade definida. Já apresentamos um exemplo com uma interface no Capítulo 6 - seção “classe interna anônima”. Neste capítulo, aprenderemos mais sobre isso. A palavra-chave “interface” é usada para definir uma interface em Kotlin conforme mostrado no seguinte trecho de código.

interface ExampleInterface {
   var myVar: String     // abstract property
   fun absMethod()       // abstract method
   fun sayHello() = "Hello there" // method with default implementation
}

No exemplo acima, criamos uma interface chamada “ExampleInterface” e dentro dela temos algumas propriedades e métodos abstratos todos juntos. Observe a função chamada “sayHello ()”, que é um método implementado.

No exemplo a seguir, implementaremos a interface acima em uma classe.

interface ExampleInterface  {
   var myVar: Int            // abstract property
   fun absMethod():String    // abstract method
   
   fun hello() {
      println("Hello there, Welcome to TutorialsPoint.Com!")
   }
}
class InterfaceImp : ExampleInterface {
   override var myVar: Int = 25
   override fun absMethod() = "Happy Learning "
}
fun main(args: Array<String>) {
   val obj = InterfaceImp()
   println("My Variable Value is = ${obj.myVar}")
   print("Calling hello(): ")
   obj.hello()
   
   print("Message from the Website-- ")
   println(obj.absMethod())
}

O trecho de código acima produzirá a seguinte saída no navegador.

My Variable Value is = 25
Calling hello(): Hello there, Welcome to TutorialsPoint.Com!
Message from the Website-- Happy Learning

Conforme mencionado anteriormente, Kotlin não oferece suporte a várias heranças, no entanto, a mesma coisa pode ser alcançada implementando mais de duas interfaces ao mesmo tempo.

No exemplo a seguir, criaremos duas interfaces e, posteriormente, implementaremos ambas as interfaces em uma classe.

interface A {
   fun printMe() {
      println(" method of interface A")
   }
}
interface B  {
   fun printMeToo() {
      println("I am another Method from interface B")
   }
}

// implements two interfaces A and B
class multipleInterfaceExample: A, B

fun main(args: Array<String>) {
   val obj = multipleInterfaceExample()
   obj.printMe()
   obj.printMeToo()
}

No exemplo acima, criamos duas interfaces de amostra A, B e na classe chamada “multipleInterfaceExample” implementamos duas interfaces declaradas anteriormente. O trecho de código acima produzirá a seguinte saída no navegador.

method of interface A
I am another Method from interface B

Neste capítulo, aprenderemos sobre os diferentes modificadores disponíveis na linguagem Kotlin. Access modifieré usado para restringir o uso das variáveis, métodos e classes usados ​​no aplicativo. Como outra linguagem de programação OOP, esse modificador é aplicável em vários lugares, como no cabeçalho da classe ou na declaração do método. Existem quatro modificadores de acesso disponíveis no Kotlin.

Privado

As classes, métodos e pacotes podem ser declarados com um modificador privado. Depois que qualquer coisa for declarada como privada, ela estará acessível em seu escopo imediato. Por exemplo, um pacote privado pode ser acessado dentro desse arquivo específico. Uma classe ou interface privada pode ser acessível apenas por seus membros de dados, etc.

private class privateExample {
   private val i = 1
   private val doSomething() {
   }
}

No exemplo acima, a classe “privateExample” e a variável i podem estar acessíveis apenas no mesmo arquivo Kotlin, onde é mencionado, pois todas são declaradas como privadas no bloco de declaração.

Protegido

Protected é outro modificador de acesso para Kotlin, que atualmente não está disponível para declaração de nível superior, já que nenhum pacote pode ser protegido. Uma classe ou interface protegida é visível apenas para sua subclasse.

class A() {
   protected val i = 1
}
class B : A() {
   fun getValue() : Int {
      return i
   }
}

No exemplo acima, a variável “i” é declarado como protegido, portanto, só é visível para sua subclasse.

interno

Internal é um modificador recém-adicionado introduzido no Kotlin. Se alguma coisa estiver marcada como interna, esse campo específico estará no campo interno. Um pacote interno é visível apenas dentro do módulo em que é implementado. Uma interface de classe interna é visível apenas por outra classe presente dentro do mesmo pacote ou módulo. No exemplo a seguir, veremos como implementar um método interno.

class internalExample {
   internal val i = 1
   internal fun doSomething() {
   }
}

No exemplo acima, o método denominado “doSomething” e a variável são mencionados como internos, portanto, esses dois campos podem ser acessíveis apenas dentro do pacote sob o qual é declarado.

Público

O modificador público pode ser acessado de qualquer lugar na área de trabalho do projeto. Se nenhum modificador de acesso for especificado, então, por padrão, ele estará no escopo público. Em todos os nossos exemplos anteriores, não mencionamos nenhum modificador, portanto, todos eles estão no escopo público. A seguir está um exemplo para entender mais sobre como declarar uma variável ou método público.

class publicExample {
   val i = 1
   fun doSomething() {
   }
}

No exemplo acima, não mencionamos nenhum modificador, portanto, todos esses métodos e variáveis ​​são públicos por padrão.

Neste capítulo, aprenderemos sobre outro novo recurso do Kotlin chamado “Extensão”. Usando a extensão, seremos capazes de adicionar ou remover algumas funcionalidades do método, mesmo sem herdá-las ou modificá-las. As extensões são resolvidas estatisticamente. Na verdade, não modifica a classe existente, mas cria uma função que pode ser chamada que pode ser chamada com uma operação de ponto.

Extensão de função

Na extensão da função, o Kotlin permite definir um método fora da classe principal. No exemplo a seguir, veremos como a extensão é implementada no nível funcional.

class Alien {
   var skills : String = "null"
	
   fun printMySkills() {
      print(skills)
   }		
}
fun main(args: Array<String>) {
   var  a1 = Alien()
   a1.skills = "JAVA"
   //a1.printMySkills()
	
   var  a2 = Alien()
   a2.skills = "SQL"
   //a2.printMySkills()
	
   var  a3 = Alien()
   a3.skills = a1.addMySkills(a2)
   a3.printMySkills()
}
fun Alien.addMySkills(a:Alien):String{
   var a4 = Alien()
   a4.skills = this.skills + " " +a.skills
   return a4.skills
}

No exemplo acima, não temos nenhum método dentro da classe “Alien” nomeado como “addMySkills ()”, no entanto, ainda estamos implementando o mesmo método em outro lugar fora da classe. Esta é a magia da extensão.

O trecho de código acima irá gerar a seguinte saída no navegador.

JAVA SQL

Extensão de Objeto

Kotlin fornece outro mecanismo para implementar a funcionalidade estática do Java. Isso pode ser feito usando a palavra-chave “objeto companheiro”. Usando este mecanismo, podemos criar um objeto de uma classe dentro de um método de fábrica e, posteriormente, podemos apenas chamar esse método usando a referência do nome da classe. No exemplo a seguir, criaremos um “objeto companheiro”.

fun main(args: Array<String>) {
   println("Heyyy!!!"+A.show())
}
class A {
   companion object {
      fun show():String {
         return("You are learning Kotlin from TutorialsPoint.com")
      }
   }
}

O trecho de código acima produzirá a seguinte saída no navegador.

Heyyy!!! You are learning Kotlin from TutorialsPoint.com

O exemplo acima parece estático em Java, no entanto, em tempo real estamos criando um objeto como uma variável membro dessa mesma classe. É por isso que também está incluído na propriedade de extensão e pode ser alternativamente chamado de extensão de objeto. Basicamente, você está estendendo o objeto da mesma classe para usar algumas das funções-membro.

Neste capítulo, aprenderemos mais sobre as classes de dados da linguagem de programação Kotlin. Uma classe pode ser marcada como uma classe de dados sempre que for marcada como ”dados”. Esse tipo de classe pode ser usado para separar os dados básicos. Além disso, ele não fornece nenhuma outra funcionalidade.

Todas as classes de dados precisam ter um construtor primário e todo o construtor primário deve ter pelo menos um parâmetro. Sempre que uma classe é marcada como dados, podemos usar algumas das funções embutidas dessa classe de dados, como “toString ()”, ”hashCode ()”, etc. Qualquer classe de dados não pode ter um modificador como abstrato e aberto ou interno. A classe de dados também pode ser estendida a outras classes. No exemplo a seguir, criaremos uma classe de dados.

fun main(args: Array<String>) {
   val book: Book = Book("Kotlin", "TutorialPoint.com", 5)
   println("Name of the Book is--"+book.name) // "Kotlin"
   println("Puclisher Name--"+book.publisher) // "TutorialPoint.com"
   println("Review of the book is--"+book.reviewScore) // 5
   book.reviewScore = 7
   println("Printing all the info all together--"+book.toString()) 
   //using inbuilt function of the data class 
   
   println("Example of the hashCode function--"+book.hashCode())
}

data class Book(val name: String, val publisher: String, var reviewScore: Int)

O trecho de código acima produzirá a seguinte saída no navegador, onde criamos uma classe de dados para conter alguns dos dados e, a partir da função principal, acessamos todos os seus membros de dados.

Name of the Book is--"Kotlin"
Puclisher Name--"TutorialPoint.com"
Review of the book is--5
Printing all the info all together--(name-Kotlin, publisher-TutorialPoint.com, reviewScore-7)
Example of the hashCode function---1753517245

Neste capítulo, aprenderemos sobre outro tipo de classe chamada classe “Selada”. Este tipo de classe é usado para representar uma hierarquia de classes restrita. Selado permite que os desenvolvedores mantenham um tipo de dados de um tipo predefinido. Para fazer uma classe selada, precisamos usar a palavra-chave “selada” como um modificador dessa classe. Uma classe selada pode ter sua própria subclasse, mas todas essas subclasses precisam ser declaradas dentro do mesmo arquivo Kotlin junto com a classe selada. No exemplo a seguir, veremos como usar uma classe selada.

sealed class MyExample {
   class OP1 : MyExample() // MyExmaple class can be of two types only
   class OP2 : MyExample()
}
fun main(args: Array<String>) {
   val obj: MyExample = MyExample.OP2() 
   
   val output = when (obj) { // defining the object of the class depending on the inuputs 
      is MyExample.OP1 -> "Option One has been chosen"
      is MyExample.OP2 -> "option Two has been chosen"
   }
   
   println(output)
}

No exemplo acima, temos uma classe lacrada chamada “MyExample”, que pode ser de apenas dois tipos - um é “OP1” e outro é “OP2”. Na classe principal, estamos criando um objeto em nossa classe e atribuindo seu tipo em tempo de execução. Agora, como essa classe “MyExample” está selada, podemos aplicar a cláusula “when” em tempo de execução para implementar a saída final.

Na classe lacrada, não precisamos usar nenhuma instrução “else” desnecessária para complexar o código. O trecho de código acima produzirá a seguinte saída no navegador.

option Two has been chosen

Como o Java, o Kotlin fornece uma ordem superior de tipagem de variável chamada de Genérica. Neste capítulo, aprenderemos como Kotlin implementa os Genéricos e como, como desenvolvedores, podemos usar as funcionalidades fornecidas na biblioteca de genéricos. Em termos de implementação, os genéricos são muito semelhantes a Java, mas o desenvolvedor Kotlin introduziu duas novas palavras-chave“out” e “in” para tornar os códigos Kotlin mais legíveis e fáceis para o desenvolvedor.

Em Kotlin, uma classe e um tipo são conceitos totalmente diferentes. Conforme o exemplo, List é uma classe em Kotlin, enquanto List <String> é um tipo em Kotlin. O exemplo a seguir descreve como os genéricos são implementados em Kotlin.

fun main(args: Array<String>) {
   val integer: Int = 1
   val number: Number = integer
   print(number)
}

No código acima, declaramos um “inteiro” e posteriormente atribuímos essa variável a uma variável numérica. Isso é possível porque “Int” é uma subclasse da classe Number, portanto, a conversão de tipo ocorre automaticamente em tempo de execução e produz a saída como “1”.

Vamos aprender mais sobre os genéricos em Kotlin. É melhor ir para o tipo de dados genérico sempre que não tivermos certeza sobre o tipo de dados que vamos usar no aplicativo. Geralmente, em Kotlin os genéricos são definidos por<T>onde “T” representa o modelo, que pode ser determinado dinamicamente pelo compilador Kotlin. No exemplo a seguir, veremos como usar tipos de dados genéricos na linguagem de programação Kotlin.

fun main(args: Array<String>) {
   var objet = genericsExample<String>("JAVA")
   var objet1 = genericsExample<Int>(10)
}
class genericsExample<T>(input:T) {
   init {
      println("I am getting called with the value "+input)
   }
}

No trecho de código acima, estamos criando uma classe com tipo de retorno genérico, que é representado como <T>. Dê uma olhada no método principal, onde definimos dinamicamente seu valor na execução, provando o tipo de valor, enquanto criamos o objeto desta classe. É assim que os genéricos são interpretados pelo compilador Kotlin. Obteremos a seguinte saída no navegador, assim que executarmos esse código em nosso campo de codificação.

I am getting called with the value JAVA
I am getting called with the value 10

Quando queremos atribuir o tipo genérico a qualquer um de seus supertipos, precisamos usar a palavra-chave “out”, e quando queremos atribuir o tipo genérico a qualquer um de seus subtipos, precisamos usar “in” palavra-chave. No exemplo a seguir, usaremos a palavra-chave “out”. Da mesma forma, você pode tentar usar a palavra-chave “in”.

fun main(args: Array<String>) {
   var objet1 = genericsExample<Int>(10)
   var object2 = genericsExample<Double>(10.00)
   println(objet1)
   println(object2)
}
class genericsExample<out T>(input:T) {
   init {
      println("I am getting called with the value "+input)
   }
}

O código acima produzirá a seguinte saída no navegador.

I am getting called with the value 10
I am getting called with the value 10.0
genericsExample@28d93b30
genericsExample@1b6d3586

Suporta Kotlin “delegation” padrão de design, introduzindo uma nova palavra-chave “by”. Usando esta palavra-chave ou metodologia de delegação, Kotlin permite que a classe derivada acesse todos os métodos públicos implementados de uma interface por meio de um objeto específico. O exemplo a seguir demonstra como isso acontece em Kotlin.

interface Base {
   fun printMe() //abstract method
}
class BaseImpl(val x: Int) : Base {
   override fun printMe() { println(x) }   //implementation of the method
}
class Derived(b: Base) : Base by b  // delegating the public method on the object b

fun main(args: Array<String>) {
   val b = BaseImpl(10)
   Derived(b).printMe() // prints 10 :: accessing the printMe() method 
}

No exemplo, temos uma interface “Base” com seu método abstrato denominado “printme ()”. Na classe BaseImpl, estamos implementando este “printme ()” e mais tarde em outra classe estamos usando esta implementação usando a palavra-chave “by”.

O trecho de código acima produzirá a seguinte saída no navegador.

10

Delegação de propriedade

Na seção anterior, aprendemos sobre o padrão de design de delegação usando a palavra-chave “por”. Nesta seção, aprenderemos sobre delegação de propriedades usando alguns métodos padrão mencionados na biblioteca Kotlin.

Delegar significa passar a responsabilidade para outra classe ou método. Quando uma propriedade já está declarada em alguns lugares, devemos reutilizar o mesmo código para inicializá-los. Nos exemplos a seguir, usaremos alguma metodologia de delegação padrão fornecida por Kotlin e algumas funções de biblioteca padrão ao implementar a delegação em nossos exemplos.

Usando Lazy ()

Lazy é uma função lambda que recebe uma propriedade como entrada e, em retorno, fornece uma instância de Lazy<T>, onde <T> é basicamente o tipo das propriedades que está usando. Vamos dar uma olhada no seguinte para entender como funciona.

val myVar: String by lazy {
   "Hello"
}
fun main(args: Array<String>) {
   println(myVar +" My dear friend")
}

No trecho de código acima, estamos passando uma variável “myVar” para a função Lazy, que em retorno atribui o valor ao seu objeto e retorna o mesmo para a função principal. A seguir está a saída no navegador.

Hello My dear friend

Delegetion.Observable ()

Observable () recebe dois argumentos para inicializar o objeto e retorna o mesmo para a função chamada. No exemplo a seguir, veremos como usar o método Observable () para implementar a delegação.

import kotlin.properties.Delegates
class User {
   var name: String by Delegates.observable("Welcome to Tutorialspoint.com") {
      prop, old, new ->
      println("$old -> $new")
   }
}
fun main(args: Array<String>) {
   val user = User()
   user.name = "first"
   user.name = "second"
}

O trecho de código acima produzirá a seguinte saída no navegador.

first -> second

Em geral, a sintaxe é a expressão após a palavra-chave “por” ser delegada. oget() e set() métodos da variável p será delegado ao seu getValue() e setValue() métodos definidos na classe Delegate.

class Example {
   var p: String by Delegate()
}

Para o trecho de código acima, a seguir está a classe delegada que precisamos gerar para atribuir o valor na variável p.

class Delegate {
   operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
      return "$thisRef, thank you for delegating '${property.name}' to me!"
   }
   operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
      println("$value has been assigned to '${property.name} in $thisRef.'")
   }
}

Durante a leitura, o método getValue () será chamado e, durante a configuração da variável, o método setValue () será chamado.

Kotlin é uma linguagem de tipo estático, portanto, as funções desempenham um grande papel nela. Estamos bastante familiarizados com a função, pois a usamos em todos os exemplos. A função é declarada com a palavra-chave “diversão”. Como qualquer outro OOP, ele também precisa de um tipo de retorno e uma lista de argumentos de opção.

No exemplo a seguir, estamos definindo uma função chamada MyFunction e da função principal estamos chamando esta função e passando alguns argumentos.

fun main(args: Array<String>) {
   println(MyFunction("tutorialsPoint.com"))
}
fun MyFunction(x: String): String {
   var c:String  = "Hey!! Welcome To ---"
   return (c+x)
}

O trecho de código acima produzirá a seguinte saída no navegador.

Hey!! Welcome To ---tutorialsPoint.com

A função deve ser declarada da seguinte forma -

fun <nameOfFunction>(<argument>:<argumentType>):<ReturnType>

A seguir estão alguns dos diferentes tipos de função disponíveis no Kotlin.

Função Lambda

Lambda é uma função de alto nível que reduz drasticamente o código do boiler plate enquanto declara uma função e define a mesma. Kotlin permite que você defina seu próprio lambda. Em Kotlin, você pode declarar seu lambda e passá-lo para uma função.

Dê uma olhada no exemplo a seguir.

fun main(args: Array<String>) {
   val mylambda :(String)->Unit  = {s:String->print(s)}
   val v:String = "TutorialsPoint.com"
   mylambda(v)
}

No código acima, criamos nosso próprio lambda conhecido como “mylambda” e passamos uma variável para este lambda, que é do tipo String e contém um valor “TutorialsPoint.com”.

O trecho de código acima produzirá a seguinte saída no navegador.

TutorialsPoint.com

Função Inline

O exemplo acima mostra o básico da expressão lambda que podemos usar no aplicativo Kotlin. Agora, podemos passar um lambda para outra função para obter nossa saída, o que torna a função de chamada uma função embutida.

Dê uma olhada no exemplo a seguir.

fun main(args: Array<String>) {
   val mylambda:(String)->Unit  = {s:String->print(s)}
   val v:String = "TutorialsPoint.com"
   myFun(v,mylambda) //passing lambda as a parameter of another function 
}
fun myFun(a :String, action: (String)->Unit) { //passing lambda 
   print("Heyyy!!!")
   action(a)// call to lambda function
}

O trecho de código acima produzirá a seguinte saída no navegador. Usando a função embutida, passamos um lambda como parâmetro. Qualquer outra função pode ser transformada em função inline usando a palavra-chave “inline”.

Heyyy!!!TutorialsPoint.com

Kotlin contém muitos recursos de outras linguagens de programação. Ele permite que você declare várias variáveis ​​de uma vez. Essa técnica é chamada de declaração de Destructuring.

A seguir está a sintaxe básica da declaração de desestruturação.

val (name, age) = person

Na sintaxe acima, criamos um objeto e definimos todos eles juntos em uma única instrução. Posteriormente, podemos usá-los da seguinte maneira.

println(name)
println(age)

Agora, vamos ver como podemos usar o mesmo em nosso aplicativo da vida real. Considere o exemplo a seguir, onde estamos criando uma classe Student com alguns atributos e posteriormente os usaremos para imprimir os valores do objeto.

fun main(args: Array<String>) {
   val s = Student("TutorialsPoint.com","Kotlin")
   val (name,subject) = s
   println("You are learning "+subject+" from "+name)
}
data class Student( val a :String,val b: String ){
   var name:String = a
   var subject:String = b
}

O trecho de código acima produzirá a seguinte saída no navegador.

You are learning Kotlin from TutorialsPoint.com

O tratamento de exceções é uma parte muito importante de uma linguagem de programação. Essa técnica restringe nosso aplicativo de gerar a saída errada em tempo de execução. Neste capítulo, aprenderemos como lidar com exceções de tempo de execução no Kotlin. As exceções em Kotlin são muito semelhantes às exceções em Java. Todas as exceções são descendentes da classe “Throwable”. O exemplo a seguir mostra como usar a técnica de tratamento de exceções em Kotlin.

fun main(args: Array<String>) {
   try {
      val myVar:Int = 12;
      val v:String = "Tutorialspoint.com";
      v.toInt();
   } catch(e:Exception) {
      e.printStackTrace();
   } finally {
      println("Exception Handeling in Kotlin");
   }
}

No trecho de código acima, declaramos uma String e, posteriormente, vinculamos essa string ao inteiro, que na verdade é uma exceção de tempo de execução. Portanto, obteremos a seguinte saída no navegador.

val myVar:Int = 12;
Exception Handeling in Kotlin

Note - Como o Java, Kotlin também executa o bloco finally após executar o bloco catch.