Primeiras aulas do curso Kotlin: lidando com exceptions e referências nulas

Kotlin: lidando com exceptions e referências nulas

Conhecendo a pilha de execução - Introdução

Eu sou o Alex Felipe, instrutor aqui na Alura, e vou apresentar para vocês o curso de Kotlin com Exceptions e Null Safety.

Para esse curso, eu vou assumir que você já tenha um conhecimento do curso “Kotlin: recursos da linguagem com pacotes e composição”, porque vamos reutilizar o mesmo projeto que foi feito durante esse curso.

Assumindo que você já tenha todo esse conhecimento que foi apresentado nesse curso. Dessa forma, dado que eu estou passando para vocês o pré-requisito, já podemos entender o que vamos ver de diferente nesse curso novo.

Nesse curso novo, como o próprio nome já diz, vamos focar bastante nessa parte de “Exceptions” e também nessa parte que é chamada de “Null Safety”. Vamos entender o que são essas “Exceptions” e porquê elas são importantes para aprendermos.

Basicamente, essas “Exceptions” são um recurso que temos no Kotlin para determinar possíveis erros que podemos ter. Não necessariamente um erro, mas algo excepcional. Algo que não deveria acontecer, só que nós precisamos lidar. Vamos ver como podemos fazer isso aqui no Kotlin.

Seja os problemas que podem acontecer no Kotlin, que são coisas que já vêm ali da biblioteca do SDK, ou as coisas nossas mesmo, como por exemplo, quando desenvolvemos o nosso projeto aqui, que foi uma simulação do Bytebank, o banco digital.

Temos uma conta que tem diversos comportamentos, que é o de saque, depósito e transferência. E no caso, para sabermos se houve um problema de saldo insuficiente, uma falha de autenticação ou então qualquer outro que seja um problema, nós não conseguimos pegar essa informação de maneira precisa. Se tivermos que notificar o nosso cliente, não conseguimos fazer.

E com as “Exceptions” vamos ver que isso é bastante possível, porque aqui nós pegamos uma situação excepcional de uma forma mais identificável. Não vai ser apenas aquele “true” ou “false”, vai ser uma falha que vai identificar: “Aconteceu uma exceção de saldo insuficiente” ou “Aconteceu uma exceção de falha de autenticação”. Vamos perceber que isso é bastante possível.

E é claro, além de saber que isso é possível, vamos saber como podemos estar lidando, porque para poder falar de “Exception”, vamos começar falando de pilha de execução. Vamos entender o que é pilha de execução e como ela é impactada quando introduzimos as “Exceptions”.

Veja que o curso é bastante focado em deixar bem claro a maneira como enxergamos e usamos as tais das “Exceptions” aqui no Kotlin.

Para finalizar o conteúdo e deixá-lo mais rico, vamos falar também sobre essa questão do null safety, que é um recurso muito importante aqui no Kotlin.

Por que ele é muito importante? Porque é um recurso que vai ter em diversos tipos de programas que você vai mexer no seu dia a dia, principalmente em plataformas, como é o caso do Android, se de repente você tiver interesse. Dessa maneira, você vai proteger o seu código dessas referências nulas que vamos ver que tem diversos problemas no nosso código, como é o caso do famoso NullPointerException.

Vamos ver que esse NullPointerException, às vezes se torna um pesadelo para muitos programadores, e vamos perceber que com o Kotlin já vai oferecer um suporte muito interessante, que é justamente esse null safety, que seria a segurança dessa referência nula.

Vamos aprender que existem ali os tipos que podem ou não ser nulos, que está falando tudo aqui na documentação. Vamos aprender as técnicas possíveis para lidar com ele, seja com “if” ou seja com os recursos disponíveis aqui dentro, para eu não dar “spoiler”. Vamos ver algumas situações nas quais podemos usar determinados recursos ou então outros recursos disponíveis.

Veja que o objetivo desse curso agora é destrinchar tudo o que temos em relação a Exceptions e o null safety com o Kotlin. Eu espero que você esteja animado para aprender esse novo conteúdo, para você avançar na sua carreira. Conto com a sua presença na nossa aula. Vamos começar? Vamos lá!

Conhecendo a pilha de execução - Introdução à pilha de execução

Como um primeiro passo, vamos falar da pilha de execução do nosso programa. Para isso, vamos utilizar aqui um exemplo que eu já deixei pronto para vocês.

É nítido notar também que vamos reutilizar o mesmo projeto do Bytebank. Se você reparar, com o código do último curso, eu já fiz aqui uma extração da função “testaAny”, que tem o mesmo código que testamos aqui a classe “Any” e seus métodos.

Então se você já fez essa extração ou se ainda não fez, faça, para deixar da mesma maneira como estamos vendo aqui. Se você quiser ver se funciona em uma boa, podemos executar, e vamos perceber que funciona sem nenhum tipo de problema. Dado que agora já passei esse feedback, podemos começar com o código que vamos testar a pilha de execução.

Antes mesmo de falar o que é pilha de execução, vamos pegar esse código que eu vou disponibilizar para vocês. Vamos apertar as teclas “Ctrl + C” e dentro do nosso arquivo “main”, vamos pegar todo o código aqui. Selecionamos com as teclas “Ctrl + A” e apertamos as teclas “Ctrl + V”, e temos o nosso código agora, para fazermos o exemplo da pilha de execução.

Vamos começar com a execução para entendermos o que temos aqui de exemplo. Veja que o código funciona sem nenhum tipo de problema e ele é bastante simples, não temos muito segredo aqui. O interessante vai ser analisar a saída para entendermos essa ideia de pilha de execução.

Para isso, o que eu vou sugerir? Que você pegue essa perspectiva que estamos vendo aqui e faça uma modificação. Qual seria essa modificação? Está vendo aqui essa “tab” do “Run”? Vamos pegá-la e direcioná-la para a direita, porque dessa maneira vamos ter o nosso código em paralelo, de maneira horizontal à saída, que é o que estamos vendo aqui. Dado que agora temos a saída, podemos analisar mais ou menos o que aconteceu.

Vamos analisar primeiro aqui, a partir do que aconteceu com o IntelliJ, que foi bastante rápido. Logo em seguida vamos ver em uma apresentação, bem passo a passo, do que aconteceu e o que está por debaixo dos panos durante essa execução.

Veja que aqui saiu essa mensagem, que é o “início main”. Logo em seguida veio para a “funcao1”. Na “funcao1” tivemos o “início funcao1”. Ele chamou a “funcao2” e então imprimiu a “funcao2”.

E a partir dessa “funcao2” ele não imprimiu nem o “fim funcao1” e nem o “fim main”. Por quê? Por que, como funciona aqui, basicamente? Ele precisa terminar a execução de uma função de um trecho de linha para ir para o próximo, e por isso ele não executou nem o “fim main” e nem o “funcao1”. Até aqui tudo bem.

Agora, quando ele entrou no “funcao2”, ele começou a imprimir o “início funcao 2” e logo em seguida ele fez a impressão desse “for” até finalizar. Então ele adicionou todos os números que foram iterados a partir desse [FOR LOOP], então é um “range” aqui, de 1 até 5. Dessa maneira, nós imprimimos todos esses números.

Depois que ele terminou o “for”, ele começou a apresentar essas mensagens de fim. Veio o “fim funcao2”, então chegando até o final aqui, ele finaliza. Depois vem o “fim funcao1”, que é esse fim depois de chamar a “funcao2”, e temos então, o “fim main” após finalizar tanto a “funcao2”, como a “funcao1”.

E o que é importante notarmos quando pegamos esse exemplo? É a ideia que está por trás da pilha de execução. Agora que fizemos essa primeira simulação, eu vou entrar em uma apresentação com o mesmo exemplo, indicando como seria a pilha por debaixo dos panos que está acontecendo a cada uma das interações que fizemos agora.

Basicamente, ao executar o nosso programa, vamos ter essa tal pilha de execução, que é algo que não precisamos representar de uma maneira física. É imaginário, mas imagine como se fosse uma pilha que você pode empilhar as coisas, que vamos ver durante a iteração.

Quando começou a fazer a primeira impressão, o que aconteceu? A JVM, que é o ambiente que estamos executando o Kotlin, começou a pegar essa função “main” e adicionou nessa tal de pilha para podermos fazer a execução, que foi esse nosso bloquinho aqui. Então esse bloquinho entrou para a pilha.

E logo no momento que ele entrou para pilha, para fazer a sua execução, percebeu que tinha que executar essa função, por isso começou com o “início main”. Em seguida, ele chamou a “funcao1”.

Quando ele chamou a “funcao1”, o que aconteceu? Ele colocou a “funcao1” também aqui, na pilha. E dado que ela entrou na pilha, ela também começou a executar as suas instruções agora, e conforme as suas instruções, tem aqui esse “print”. Logo depois vem a “funcao2”. Então quando chegou na “funcao2”, também adicionou aqui. essa pilha.

E como podemos ver, cada função que é chamada, vai adicionando aqui na pilha de execução. Internamente, também na “funcao1”, por exemplo, ela também vai adicionar os seus “prints” da mesma maneira. A “funcao2” também vai adicionar tanto os seus “prints”, o [FOR LOOP], como também o seu “print” final. É mais ou menos dessa maneira que funciona aqui.

Esse trecho de código, que é essa função, vai ter todo esse trecho aqui. O trecho da “funcao1” vai ter tanto o trecho dela, o trecho da “funcao2”, como também o seu final de trecho. E o “main” vai comportar todos, mas ele só vai ser executado no final, assim que terminar toda a pilha.

Por exemplo: chegando no final da pilha aqui da “funcao2”, o que vai acontecer? Vamos executar o nosso programa, vamos terminar a “funcao2” e vamos continuar com a “funcao1”, como podemos ver aqui. E quando ele finaliza a “funcao1”, ele volta para o fim do “main”.

E chegando no fim do “main”, o que vai acontecer? Ele vai apresentar aquela mensagem que o processo foi finalizado com o código “0”. Eu ainda não dei tanto feedback em relação à essa questão do código “0”. Agora eu vou falar a respeito dele também.

Quando ele indica que teve esse código “0”, significa para o sistema, como o software que controla todos os nossos programas - que nesse caso aqui é o Windows, poderia ser Linux e assim por diante - que o processo foi finalizado com sucesso e o nosso programa foi executado sem nenhum tipo de problema. Então é bastante importante também notarmos esse tipo de informação. É dessa maneira que funciona a pilha de execução.

Como um resumo, basicamente vamos ter esse estado inicial da nossa pilha de execução, então esse meio, que é o ciclo. Também essa pilha de execução é chamada como “call stack” e aqui vamos começar com o “main”. Logo em seguida vamos ter a “funcao1” empilhada e vamos ter então a “funcao2” empilhada.

Novamente, se estivéssemos em um programa mais complexo, todas as funções que aparecessem seriam empilhadas. Depois que elas fossem executadas, voltariam para as outras funções e assim por diante.

Então, chegando na “funcao2”, ao ser finalizada vem a “funcao1”, ao ser finalizado o “main”, e então, acaba aí o nosso programa. Essa é a introdução na nossa pilha de execução.

E agora que temos essa informação, a seguir vamos falar a respeito das tais das “Exceptions” em relação à essa pilha de execução. Vamos ver que é necessário conhecer isso para vermos o impacto que uma exceção tem dentro do nosso programa.

Conhecendo a pilha de execução - Executando programa com depurador

Agora que conhecemos a pilha de execução na teoria, eu vou mostrar para vocês uma técnica na prática que podemos fazer a simulação dessa pilha de execução e vê-la acontecendo da mesma maneira, como vimos aqui na teoria. Só que vamos utilizar o IntelliJ como recurso para fazermos essa verificação.

Voltando no IntelliJ, o que eu vou ensinar para vocês é uma técnica que é muito comum de ser utilizada pelas pessoas que desenvolvem código, que também é conhecida como depurador ou então, “debugging”.

Essa técnica tem a ideia de inspecionar cada coisa que acontece durante a execução do nosso código, linha por linha. Ela dá muita informação, assim como vimos na pilha de execução, como também outras coisas que vamos ver durante esse vídeo. Então vamos começar!

Agora vem a questão, como utilizamos esse tal depurador? Para isso, vamos ter aqui esse botão de execução, que é esse que estamos vendo aqui, que é justamente o “bug”, um inseto.

Se clicarmos nele, o que vai acontecer? O nosso programa é executado da mesma maneira como executamos em uma execução normal. Tanto que eu vou fechar esse [RUN] que estamos vendo aqui e eu vou pegar esse “Debug” que ele abriu para nós quando foi executado, e colocá-lo aqui, à direita.

E vamos perceber que ele tem uma perspectiva diferente do que vimos até então, só que ele vai fazer a impressão no nosso programa da mesma maneira de antes, com mais informações, indicando ali que você conectou a VM e assim por diante. Até então, não é tão interessante de sabermos. Depois ele fala que desconectou da VM, indicando que o processo foi finalizado com sucesso.

Então não tivemos aqui nenhuma diferença apenas executando o “Debug”, sem fazer nenhum tipo de alteração. Só que vamos perceber que com o “Debug”, precisamos fazer aqui alguns passos antes de fazer a sua chamada, para então fazer o uso do seu poder. É isso que eu vou mostrar para vocês!

Para isso, eu vou realmente pegar o nosso código e vou minimizar. Minimizando o nosso código, o que nós conseguimos fazer para podermos utilizar o “Debug” de uma maneira que seja mais interessante e que consigamos usufruir do que vamos fazer?

Para isso. primeiro precisamos marcar qual é o ponto do código que ele precisa dar início na inspeção. E para isso, podemos usar um marcador, que pode ser adicionado a partir das linhas do nosso código. Nessa parte que fica entre o número da linha e entre o nosso código, ou então entre essa barrinha azul, como vocês estão vendo.

Clicando uma vez, ele mostra essa bolinha vermelha. Essa bolinha vermelha também é conhecida como “breakpoint”, que nada mais é do que um ponto no qual estamos indicando: “Se você executar o depurador ou o ‘Debugging’, é por aqui que você precisa começar a realizar a inspeção”.

Então se clicarmos novamente no “bug”, ele vai fazer a mesma coisa de antes, só que ele só vai indicar a mensagem que foi conectada aqui na VM. Por que ele está fazendo isso? Porque no momento que ele enxerga um “breakpoint”, que é justamente esse ponto aqui para ele parar, ele não vai fazer mais nada aqui no nosso programa, a não ser que falemos para ele fazer.

Então, agora que conseguimos parar o nosso “Debug”, para ele começar a fazer a inspeção, vamos trabalhar mais nessa perspectiva do “Debugging”. O que vamos fazer aqui? Eu estou até estendendo um pouco mais, para termos mais informações.

Basicamente, vamos utilizar alguns dos recursos e vamos conhecer o que cada um desses pontos significa, para entendermos a ideia da pilha de execução, agora na prática. Então vamos lá!

Veja que aqui temos diversos botões para fazer uma iteração com o “Debug”. Vamos ver só um pouquinho deles para realmente vermos o mínimo que é necessário. O ponto que eu quero focar com vocês é na parte aqui do console, que é a saída.

E também nessa parte dos “frames”, que indica a nossa pilha. Como podemos ver, a nossa pilha está indicando a função “main” na linha “4”. Então observe bastante o que está acontecendo durante essa parte dos “frames”.

Essa parte de variáveis não precisamos ver tanto, porque iríamos falar mais a respeito do “Debug”. O que ele pode nos ajudar, não é muito o objetivo do curso. Vamos focar mais nessa parte de “frames”, a nossa saída e também esses botões que podemos estar utilizando.

Dos botões que vamos utilizar, vai ser esse “Step Over” e esse “Step Into”, que com o atalho ficam nas teclas “F8” e “F7”. Eu vou pelo clique, que são as nossas primeiras vezes aqui, então não vou muito por essa ideia de fazer por atalho, porque também não é muito o objetivo de potencializar o nosso uso com o “Debugging”.

Primeiro eu vou clicar nesse “Step Over”, para vermos o que vai acontecer. Clicando uma vez, ele passou para a próxima linha. Então ele executou o “print” ali, ao executar, ele nos mostrou aqui. Clicando mais uma vez, olhe só o que vai acontecer, o “Step Over” sempre vai passar para a próxima linha do que temos aqui da execução da nossa função.

Então, ao invés de entrar na “funcao1”, ele já foi para o “print”, e indo para o “print”, realmente ele já executou aqui todas as outras funções. Porque a “funcao1” executa o início e o fim dela, junto com a “funcao2”. Então aqui ainda não conseguimos fazer a iteração, tivemos a mesma impressão de fazer uma execução normal.

E fazendo novamente o nosso “Step Over”, nós finalizamos o nosso programa. Na verdade, ele entra nessa última instrução, mais um. Ele finaliza o nosso programa e o mesmo resultado de antes.

Então não foi tão interessante assim, porque o “Step Over” sempre vai passando a próxima linha, só que executando novamente, clicando no próprio insetinho que fica agora à esquerda, nós voltamos ali para a execução do “Debug”.

E executando agora com o nosso “Step Into”, ele vai executar aqui um “print”, só que agora que é uma função nossa, que é esse “funcao1”, clicando no “Step Into”, ele vai entrar na função.

E agora que a coisa começa a ficar interessante para nós, porque ao entrar na “funcao1”, aqui nos “frames”, ele mostrou que na nossa pilha de execução. A “funcao1” na linha “10” foi adicionada, que foi aquilo que vimos na apresentação. Agora sim, já ficou bastante interessante para o que precisamos entender de pilha!

Por que ficou interessante? Porque também, se de repente você estiver nos seus programas, você consegue fazer esse tipo de inspeção e pegar passo a passo aqui do seu programa, utilizando o “Debugging”. Isso é bastante útil nos momentos em que você, às vezes não entende muito o que está acontecendo no seu programa ou de repente aconteceu algo que você precisa investigar, com a ferramenta “Debug” você consegue fazer isso.

No nosso caso, estamos avaliando a pilha de execução, mas você pode usar sim para o seu dia a dia, o que é muito comum. Então vamos continuar com o nosso “Step Into”. Passando agora, “Step Into” do nosso “print” ali dentro da “funcao1”, ele mostrou aqui a mensagem, olhe só que legal.

Nós agora vamos para a “funcao2” com o “Step Into”, porque se colocarmos o “Step Over”, ele volta para a próxima linha e nós não vemos a execução passo a passo da “funcao2”. Então, “Step Into”.

Olhe só que legal! Agora vamos ter na pilha de execução a “funcao2” na linha “16” e parou na “funcao1” na linha “11”. Isso que é um ponto muito interessante de notarmos, porque aqui vai passo a passo, e nós vemos que essa pilha de execução existe.

Continuando no “Step Into”, temos a “funcao2” e agora, “Step Into”, temos o “for”, para ele poder entrar também temos que fazer o “Step Into”, para ele fazer cada uma das interações. O IntelliJ já mostra aqui as variáveis, nos indicando que começou com o valor “1” na variável “i”.

Então podemos passar agora o “Step Into” e ele vai para cada uma das [INTERAÇÕES], olhe só que interessante. Ele executa, tudo isso está na nossa pilha, então ele fica na linha “17”, vai para a “18”. “17” e “18” até finalizar o ciclo do nosso [FOR LOOP].

Finalizando, ele vai para “funcao2”, linha “20” e depois da nossa linha “20” para a “21”, porque é o último passo da instrução. Agora, se nós fazemos mais um “Step Into”, ele sai da nossa “funcao2”, ele sai da pilha. Perceba que essa pilha existe. Na prática nós provamos que isso acontece.

Agora vamos para o “Step Into” até o final aqui. Ele sai da nossa “funcao1”, volta para mim, “Step Into” novamente. “Step Into”, ele finaliza o nosso programa, indicando que o código foi “0”.

Perceba que fizemos exatamente a mesma simulação que aconteceu na teoria, agora na prática, isso utilizando o “Debug”. É claro, utilizamos o “Debug” para provarmos que existe essa pilha, para podermos mostrar para vocês que essa pilha vai ser bastante comum no dia a dia de vocês. Se de repente você inspecionar um programa e quiser entender o momento do código em que aconteceu algum problema, você conseguirá verificar dessa maneira.

É dessa maneira que você precisa enxergar e avaliar, porque agora que temos toda essa teoria e também agora conhecemos na prática como funciona, é natural partirmos para o próximo passo, que é entender de fato o que é uma “Exception” e o que ela causa de problema para o nosso programa.

Então, agora sim! A seguir vamos ver sobre isso.

Sobre o curso Kotlin: lidando com exceptions e referências nulas

O curso Kotlin: lidando com exceptions e referências nulas possui 137 minutos de vídeos, em um total de 45 atividades. Gostou? Conheça nossos outros cursos de Kotlin em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Kotlin acessando integralmente esse e outros cursos, comece hoje!

Plus

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$85
à vista R$1.020
Matricule-se

Pro

  • Acesso a TODOS os cursos da plataforma

    Mais de 1200 cursos completamente atualizados, com novos lançamentos todas as semanas, em Programação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

12X
R$120
à vista R$1.440
Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas