Você pode usar Java para construir servidores, criar aplicativos desktop, jogos, aplicativos mobile e muito mais. Existem também outras linguagens JVM (discutiremos o que isso significa em breve), como Kotlin , Groovy , Scala e Clojure, que você pode usar para diferentes propósitos.
Java também é multiplataforma, o que significa que o código que você escreve e compila em uma plataforma pode ser executado em qualquer outra plataforma que tenha Java instalado. Discutiremos esse tópico com mais detalhes posteriormente.
Por enquanto, posso dizer que, embora o Java tenha sua cota de falhas, ele também tem muito a oferecer.
Índice
- Pré-requisitos
- Como escrever Hello World em Java
- O que está acontecendo no código?
- O que é JVM?
- O que é JRE e JDK?
- Como configurar o Java no seu computador?
- Como instalar um IDE Java no seu computador?
- Como criar um novo projeto no IntelliJ IDEA
- Como trabalhar com variáveis em Java
- Quais são as regras para declarar variáveis?
- O que são variáveis finais?
- Quais são os tipos de dados primitivos em Java?
- O que é conversão ou conversão de tipo?
- O que são classes wrapper em Java
- Como usar operadores em Java
- O que são operadores aritméticos?
- O que são os operadores de atribuição?
- O que são operadores relacionais?
- O que são operadores lógicos?
- O que são operadores unitários?
- Como trabalhar com strings em Java
- Como formatar uma string
- Como obter o comprimento de uma string ou verificar se ela está vazia ou não
- Como dividir e unir cordas
- Como converter uma string para autoridades ou minúsculas
- Como comparar duas strings
- Como substituir caracteres ou substrings em uma string
- Como verificar se uma string contém uma substring ou não
- Quais são as diferentes maneiras de inserir e enviar dados?
- Como usar instruções condicionais em Java
- O que é uma instrução switch-case?
- Qual é o escopo de variável em Java?
- Quais são os valores padrões das variáveis em Java?
- Como trabalhar com matrizes em Java
- Como classificar uma matriz
- Como realizar uma pesquisa binária em uma matriz
- Como preencher uma matriz
- Como fazer cópia de um array
- Como comparar dois arrays
- Como usar loops em Java
- Para Laço
- Loop para cada
- Enquanto Laço
- Laço Do-While
- Como trabalhar com listas de array em Java
- Como adicionar ou remover vários elementos
- Como remover elementos com base em uma condição
- Como clonar e comparar listas de array
- Como verificar se um elemento está presente ou se a lista de matrizes está vazia
- Como classificar uma lista de matriz
- Como manter elementos comuns de duas listas de array
- Como executar uma ação em todos os elementos de uma lista de matriz
- Como trabalhar com mapas de hash em Java
- Como colocar ou substituir vários elementos em um mapa de hash
- Como verificar se um mapa de hash contém um item ou se está vazio
- Como executar uma ação em todos os elementos de um mapa de hash
- Classes e Objetos em Java
- O que é um método?
- O que é sobrecarga de método?
- O que são construtores em Java?
- O que são modificadores de acesso em Java?
- O que são os métodos Getter e Setter em Java?
- O que é herança em Java?
- Como substituir um método em Java
- Conclusão
Pré-requisitos
O único requisito para este curso é familiaridade com qualquer outra linguagem de programação, como Python, JavaScript e assim por diante.
Embora eu explique conceitos cruciais de programação no contexto de Java, não expliquei coisas como o que é uma variável no contexto da programação em geral.
Como escrever Hello World em Java
O ideal seria que o primeiro passo fosse configurar o Java no seu computador, mas não quero te entender como baixar e instalar um monte de software logo de cara. Para este exemplo, você usará https://replit.com/ como plataforma.
Primeiro, acesse https://replit.com/ e crie uma nova conta, caso ainda não tenha uma. Você pode usar sua conta atual do Google/GitHub/Facebook para fazer login. Após o login, você será direcionado para sua página inicial. Lá, use o botão Criar em Meus Reps para criar um novo representante.
No modal Criar um Repl , escolha Java como Modelo, defina um Título descritivo como HelloWorld e clique no botão Criar Repl .
Um editor de código será exibido com um terminal integrado da seguinte maneira:
No lado esquerdo está a lista de arquivos neste projeto, no meio está o editor de código e no lado direito está o terminal.
O modelo vem com algum código por padrão. Você pode repeti-lo clicando no botão Executar . Vá em frente e execute o programa.
Se tudo correr bem, você verá as palavras "Olá, mundo!" impressas no lado direito. Parabéns, você executou seu primeiro programa Java com sucesso.
O que está acontecendo no código?
O programa hello world é provavelmente o programa Java mais básico que você pode escrever – e entender esse programa é crucial.
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
Vamos começar com a primeira linha:
class Main {
//...
}
Esta linha cria uma Main
classe. Uma classe agrupa um conjunto de códigos relacionados em uma única unidade.
Esta é uma public
classe, o que significa que pode ser acessada em qualquer lugar da base de código. Um arquivo-fonte Java (arquivos com extensão .js) pode conter apenas uma classe .java
de nível superior .public
Esta classe pública de nível superior deve ter o mesmo nome do arquivo de código-fonte. É por isso que o arquivo nomeado Main.java
contém a main
classe neste projeto.
Para entender o porquê, clique nos três pontos na lista de arquivos e clique na opção Mostrar arquivos ocultos .
Isso revelará alguns novos arquivos dentro do projeto. Entre eles está o Main.class
arquivo. Ele é chamado de bytecode. Ao clicar no botão Executar, o compilador Java compilou o código do Main.java
arquivo para este bytecode.
Agora, modifique o código Hello World existente da seguinte forma:
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
class NotMain {
public static void main(String[] args) {
System.out.println("Not hello world!");
}
}
Como você pode ver, uma nova classe chamada NotMain
foi adicionada. Vá em frente e clique no botão Executar mais uma vez, mantendo os olhos no menu Arquivos .
Um novo bytecode chamado NotMain.class
apareceu. Isso significa que, para cada classe que você tiver em toda a sua base de código, o compilador criará um bytecode separado.
Isso cria confusão sobre qual classe é o ponto de entrada para este programa. Para resolver esse problema, o Java usa uma classe que corresponde ao nome do arquivo de código-fonte como ponto de entrada para este programa.
Chega de falar da aula, agora vamos dar uma olhada na função dentro dela:
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
A public static void main (String[] args)
função é especial em Java. Se você tem experiência com linguagens como C, C++ ou Go, já deve saber que todo programa nessas linguagens tem uma função principal. A execução do programa começa a partir dessa função principal.
Em Java, você precisa escrever essa função exatamente como está, public static void main (String[] args)
caso contrário ela não funcionará. Aliás, se você alterar, mesmo que seja só um minuto, o Java começa a gritar.
O tipo de retorno mudou de void
para int
a função agora retorna 0
no final. Como você pode ver no console, ele diz:
Error: Main method must return a value of type void in class Main, please
define the main method as:
public static void main(String[] args)
Ouça essa sugestão e reverta seu programa para como ele era antes.
class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
O main
método é um public
método e, static
portanto, você pode chamá-lo sem instanciar sua classe.
Isso void
significa que a função não retorna nenhum valor e que String[] args
a função recebe um array de strings como argumento. Esse array contém argumentos de linha de comando passados ao programa durante uma execução.
Imprime System.out.println
strings sem terminal. No exemplo acima, " "Hello world!"
foi passado para a função", então você recebe Hello world!
uma string impressa no terminal.
Em Java, toda instrução termina com um ponto e vírgula. Ao contrário de JavaScript ou Python, o ponto e vírgula em Java é obrigatório . Deixar um de fora causará falha na construção.
É basicamente isso para este programa. Se você não entendeu cada aspecto desta seção palavra por palavra, não se preocupe. As coisas ficarão muito mais claras à medida que você avança.
Por enquanto, lembre-se de que o nível superior public class
em um arquivo de origem Java deve corresponder ao nome do arquivo, e a função principal de qualquer programa Java deve ser definida como public static void main(String[] args)
.
O que é JVM?
Já mencionei a palavra "bytecode" algumas vezes na seção anterior. Também disse que Java é "multiplataforma", o que significa que o código escrito e compilado em uma plataforma pode ser executado em qualquer plataforma que tenha Java instalado.
Veja bem, seu processador não entende inglês. Na verdade, a única coisa que ele entende são zeros e uns, também conhecidos como binários.
Quando você escreve e compila um programa em C++, ele resulta em um arquivo binário. Seu processador o entende e, dependendo da plataforma de destino do programa, esse arquivo pode ser diferente.
Tomemos como exemplo um processador AMD64 e um ARMv8-A. Esses processadores têm conjuntos de instruções diferentes. Portanto, para executar seu programa nessas duas plataformas diferentes, você terá que compilá-los separadamente.
Mas um programa Java pode ser escrito uma vez e executado em qualquer lugar. Espero que você se lembre dos bytecodes que mencionamos na seção anterior. Quando você compila código Java, ele não resulta em binário, mas sim em bytecode.
Este bytecode não é totalmente binário, mas também não é legível por humanos. Aliás, seu processador também não consegue lê-lo.
Então, em vez de enviar esse bytecode para a CPU, nós o executamos na Máquina Virtual Java (JVM). A JVM então lê e interpreta o bytecode para a CPU.
Se você quiser entender a arquitetura da JVM em um nível mais profundo, sugiro o artigo detalhado de Siben Nayak sobre o assunto.
O que é JRE e JDK?
JRE significa Java Runtime Environment e JDK significa Java Development Kit.
O JRE ou Java Runtime Environment reúne uma implementação da JVM junto com um conjunto de bibliotecas necessárias para executar programas Java.
O JDK, por outro lado, empacota o JRE junto com todas as bibliotecas necessárias para desenvolver programas Java.
Então, se você quiser executar programas Java no seu computador, instale o JRE. Se quiser desenvolver programas Java você mesmo, instale o JDK. Existem várias implementações do JDK.
Existe o Java SE (Standard Edition) Development Kit da Oracle e o OpenJDK , uma implementação de referência oficial do Java SE (Standard Edition) Development Kit.
Como você pode perceber pelo nome do OpenJDK, ele é de código aberto. Portanto, existem várias versões dele. Se você estiver em uma máquina Linux e usar o gerenciador de pacotes de sua distribuição para instalar o JDK, é bem provável que você instale uma versão do OpenJDK, como Adoptium , Microsoft Build do OpenJDK e assim por diante.
Espero que você entenda que o JRE é um superconjunto da JVM e o JDK é um superconjunto do JRE. Não se preocupe com implementações ou compilações diferentes no momento, você terá quando chegar a hora.
Como configurar o Java no seu computador
Primeiro, acesse https://www.oracle.com/java/technologies/downloads/ e baixe a versão mais recente do Java SE Development Kit de acordo com a plataforma em que você está:
Após a conclusão do download, inicie o instalador e siga o processo de instalação clicando no botão Avançar. Conclua clicando no botão Fechar na última página.
O processo de instalação pode variar no macOS e no Linux, mas você deve descobrir sozinho.
Após a conclusão do comando de instalação, execute o seguinte em seu terminal:
java --version
# java 18.0.2 2022-07-19
# Java(TM) SE Runtime Environment (build 18.0.2+9-61)
# Java HotSpot(TM) 64-Bit Server VM (build 18.0.2+9-61, mixed mode, sharing)
Para funcionar, você instalou o Java SE Development Kit em seu computador com sucesso. Se preferir usar o OpenJDK, sinta-se à vontade para baixar a versão da Microsoft do OpenJDK ou o Adoptium e siga o processo de instalação.
Para os programas de exemplo simples que escreveremos neste artigo, não importa qual JDK você está usando. Mas, na prática, comprovou-se que sua versão do JDK funciona perfeitamente com o tipo de projeto em que você está trabalhando.
Como instalar um IDE Java no seu computador
Quando se trata de Java, o IntelliJ IDEA é inegavelmente o melhor IDE disponível. Até o Google o utiliza como base para o Android Studio .
A versão final do IDE pode custar até US$ 149,00 por ano para um indivíduo . Mas se você for estudante, pode obter licenças educacionais para todos os produtos JetBrains gratuitamente.
Há também uma edição comunitária, totalmente gratuita e de código aberto. É a que usaremos ao longo de todo o livro.
Acesse a página de download do IntelliJ IDEA e baixe a edição da comunidade para sua plataforma.
Quando o download terminar, use o instalador para instalar o IntelliJ IDEA como qualquer outro software.
Como criar um novo projeto no IntelliJ IDEA
Use o atalho do menu Iniciar para iniciar o IntelliJ IDEA. A seguinte janela será exibida:
Use o botão Novo Projeto e uma janela Novo Projeto será exibida:
Dê um nome descritivo ao seu projeto. Deixe as demais opções como estão e clique no botão Criar .
A criação do projeto não deve levar mais do que alguns instantes e, quando estiver concluída, a seguinte janela será exibida:
Esta é a janela de ferramentas do projeto no lado esquerdo. Todo o seu código-fonte ficará dentro dessa src
pasta.
Clique com o botão direito do mouse na src
pasta e vá em Novo > Classe Java .
Na próxima etapa, coloque um nome, como Main
para sua classe, e certifique-se de que Classe esteja destacado como o tipo.
Uma nova classe será criada com algumas linhas de código.
Atualize o código da seguinte maneira:
public class Main {
public static void main (String[] args) {
System.out.println("Hello World!");
}
}
Para executar este código, use o botão verde de reprodução no lado direito da barra superior.
O código será executado e a saída será exibida no terminal integrado na parte inferior da janela.
Parabéns, você recriou com sucesso o HelloWorld
programa discutido anteriormente no IntelliJ IDEA.
Como trabalhar com variáveis em Java
Para trabalhar com diferentes tipos de dados em Java, você pode criar variáveis de diferentes tipos. Por exemplo, se quiser armazenar sua idade em uma nova variável, faça assim:
public class Main {
public static void main(String[] args) {
//
int age;
}
}
Comece escrevendo o tipo de dado ou variável. Como age
é um número inteiro, seu tipo será inteiro ou, int
para abreviar, seguido pelo nome da variável age
e um ponto e vírgula.
No momento, você declarou a variável, mas não a inicializou. Em outras palavras, a variável não possui valor. Você pode inicializá-la da seguinte maneira:
public class Main {
public static void main(String[] args) {
//
int age;
// =
age = 27;
// prints the age on the terminal
System.out.println("I am " + age + " years old.");
}
}
Ao atribuir um valor, comece escrevendo o nome da variável que deseja inicializar, seguido por um sinal de igual (chamado operador de atribuição) e, em seguida, o valor que deseja atribuir à variável. E não se esqueça do ponto e vírgula no final.
A System.out.println();
chamada de função imprimirá a linha I am 27 years old.
no console. Caso você esteja se perguntando, usar um sinal de mais é uma das muitas maneiras de imprimir variáveis dinamicamente no meio de uma frase.
Uma coisa que você precisa ter em mente é que não é possível usar uma variável não inicializada em Java. Portanto, se você comentar a linha age = 27
colocando duas barras antes dela e tentar compilar o código, o compilador exibirá a seguinte mensagem de erro:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The local variable age may not have been initialized
at variables.Main.main(Main.java:13)
A linha The local variable age may not have been initialized
indica que a variável não foi inicializada.
Em vez de declarar e inicializar a variável em linhas diferentes, você pode fazer isso de uma só vez, da seguinte maneira:
public class Main {
public static void main(String[] args) {
// =
int age = 27;
// prints the age on the terminal
System.out.println("I am " + age + " years old.");
}
}
O código deve voltar ao normal. Além disso, você pode alterar o valor de uma variável quantas vezes quiser no seu código.
public class Main {
public static void main(String[] args) {
int age = 27;
// updates the value to be 28 instead of 27
age = 28;
System.out.println("I am " + age + " years old.");
}
}
Neste código, o valor de age
mudará de 27 para 28 porque você o está substituindo antes da impressão.
Tenha em mente que, embora você possa atribuir valores a uma variável quantas vezes quiser, não é possível declarar a mesma variável duas vezes.
public class Main {
public static void main(String[] args) {
// =
int age = 27;
int age = 28;
// prints the age on the terminal
System.out.println("I am " + age + " years old.");
}
}
Se você tentar compilar este código, o compilador exibirá a seguinte mensagem de erro:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Duplicate local variable age
at variables.Main.main(Main.java:9)
A linha Duplicate local variable age
indica que a variável já foi declarada.
Além de variáveis, você pode encontrar o termo "literal" na internet. Literais são variáveis com valores fixos.
Por exemplo, aqui, age = 27
e não é calculado dinamicamente. Você escreveu o valor diretamente no código-fonte. Assim age
como um literal inteiro.
Quais são as regras para declarar variáveis?
Existem algumas regras quando se trata de nomear variáveis em Java. Você pode nomeá-los com qualquer nome, desde que não comece com um número e não possa conter espaços.
Embora seja possível iniciar um nome de variável com um sublinhado (_) ou um cifrão ($), não se atentar ao uso deles pode dificultar a leitura do código. Nomes de variáveis também diferenciam fronteiras de mineiras. Portanto, age
e AGE
são duas variáveis diferentes.
Outra coisa importante a lembrar é que você não pode usar nenhuma das palavras-chave reservadas pelo Java. Existem cerca de 50 delas atualmente. Você pode aprender sobre essas palavras-chave na documentação oficial, mas não se preocupe em memorizá-las.
À medida que você pratica, informações importantes serão infiltradas em seus neurônios automaticamente. E se você ainda errar na declaração de uma variável, o compilador estará lá para lembrá-lo de que algo está errado.
Além das regras, existem algumas convenções que você deve seguir:
- Comece o nome da sua variável com uma letra minúscula e nenhum caractere especial (como um sublinhado ou um cifrão).
- Se o nome da variável tiver várias palavras, use camel case:
firstName
,lastName
- Não use nomes com uma única letra:
f
,l
Contanto que você siga essas regras e convenções, está tudo certo. Se quiser saber mais sobre convenções de nomenclatura em geral, confira meu artigo sobre o assunto .
O que são final
variáveis?
Uma final
variável em Java só pode ser inicializada uma vez. Portanto, se você declarar uma variável como final
, não poderá reatribuí-la.
public class Main {
public static void main(String[] args) {
// final =
final int age = 27;
age = 28;
System.out.println("I am " + age + " years old.");
}
}
Como a age
variável foi declarada como final
, o código exibirá a seguinte mensagem de erro:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The final local variable age cannot be assigned. It must be blank and not using a compound assignment
at variables.Main.main(Main.java:9)
Entretanto, se você deixar uma variável não inicializada durante a declaração, o código funcionará:
public class Main {
public static void main(String[] args) {
// final
final int age;
age = 28;
// prints the age on the terminal
System.out.println("I am " + age + " years old.");
}
}
Portanto, declare uma variável como final
________ limitará sua capacidade de reatribuir seu valor. Se você deixá-la sem inicializar, poderá inicializá-la normalmente.
Quais são os tipos de dados primitivos em Java?
Em um nível mais alto, existem dois tipos de dados em Java: os "tipos primitivos" e os "tipos não primitivos" ou "tipos de referência".
Tipos primitivos armazenam valores. Por exemplo, int
é um tipo primitivo e armazena um valor inteiro.
Um tipo de referência, por outro lado, armazena a referência em um local de memória onde um objeto sonoro está sendo armazenado.
Existem oito tipos de dados primitivos em Java.
TIPO | EXPLICAÇÃO |
byte |
Inteiro assinado de 8 bits no intervalo de -128 a 127 |
short |
Inteiro assinado de 16 bits no intervalo de -32.768 a 32.767 |
int |
Inteiro assinado de 32 bits no intervalo de -2147483648 a 2147483647 |
long |
Inteiro assinado de 64 bits no intervalo de -9223372036854775808 a 9223372036854775807 |
float |
ponto flutuante de 32 bits de precisão simples dentro do intervalo de 1,4E-45 a 3,4028235E38 |
double |
ponto flutuante de 64 bits de precisão dupla dentro do intervalo de 4,9E-324 a 1,7976931348623157E308 |
boolean |
Pode ser qualquer um true ou false |
char |
caractere Unicode único de 16 bits no intervalo de u0000 (ou 0) a uffff (ou 65.535 inclusive) |
Sim, sim, eu sei que a tabela parece assustadora, mas não se estresse. Você não precisa decorá-los.
Você não precisará pensar sobre esses intervalos com muita frequência e, mesmo que precise, há maneiras de imprimi-los no seu código Java.
Entretanto, se você não entende o que é um bit, eu recomendaria este pequeno artigo para aprender sobre binário.
Você já aprendeu sobre como declarar um inteiro na seção anterior. Você pode declarar um byte
, short
, e long
da mesma forma.
Declarar a double
também funciona da mesma maneira, exceto que você pode atribuir um número com um ponto decimal em vez de um inteiro:
public class Main {
public static void main(String[] args) {
double gpa = 4.8;
System.out.println("My GPA is " + gpa + ".");
}
}
Se você atribuir um int
ao double
, como 4
em vez de 4.8
, a saída será 4.0
em vez de 4
, porque double
sempre terá um ponto decimal.
Como double
e float
são semelhantes, você pode pensar que substituir a double
palavra-chave por float
converterá essa variável para um número de ponto flutuante – mas isso não é correto. Você terá que adicionar um f
ou F
após o valor:
public class Main {
public static void main(String[] args) {
float gpa = 4.8f;
System.out.println("My GPA is " + gpa + ".");
}
}
Isso acontece porque, por padrão, todo número com vírgula decimal é tratado como um double
em Java. Se você não anexar o f
, o compilador pensará que você está tentando atribuir um double
valor a uma float
variável.
boolean
os dados podem conter valores true
ou false
.
public class Main {
public static void main(String[] args) {
boolean isWeekend = false;
System.out.println(isWeekend); // false
}
}
Como você pode imaginar, false
pode ser tratado como um não e true
pode ser tratado como um sim.
Os booleanos se tornarão muito mais úteis depois que você aprender sobre instruções condicionais. Então, por enquanto, lembre-se apenas do que elas são e o que podem conter.
O char
tipo pode conter qualquer caractere Unicode dentro de um determinado intervalo.
public class Main {
public static void main(String[] args) {
char percentSign = '%';
System.out.println(percentSign); // %
}
}
Neste exemplo, você salvou o sinal de porcentagem dentro de uma char
variável e o imprimiu no terminal.
Você também pode usar sequências de escape Unicode para imprimir determinados símbolos.
public class Main {
public static void main(String[] args) {
char copyrightSymbol = 'u00A9';
System.out.println(copyrightSymbol); // ©
}
}
A sequência de escape Unicode para o símbolo de direitos autorais, por exemplo, é u00A9
e você pode encontrar mais sequências de escape Unicode neste site .
Dentre esses 8 tipos de dados, você trabalhará com int
, double
, boolean
e char
na maioria das vezes.
O que é conversão ou conversão de tipo?
A conversão de tipos em Java pode ser "implícita" ou "explícita". Quando o compilador converte automaticamente um tipo menor de dado em um maior, isso é conhecido como conversão implícita ou de restrição.
public class Main {
public static void main(String[] args) {
int number1 = 8;
double number2 = number1;
System.out.println(number2); // 8.0
}
}
Como um double é maior que um inteiro, o compilador poderia facilmente realizar a conversão. Se você tentar fazer o inverso, no entanto, encontrará o seguinte erro do compilador:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Type mismatch: cannot convert from double to int
at operators.Main.main(Main.java:7)
Ao executar uma conversão implícita, o fluxo de conversão deve ser o seguinte:
Você pode, é claro, ir de um short
para um double
, por exemplo, pulando os outros no meio.
Você também pode migrar de tipos de dados menores para maiores. Isso é chamado de conversão de tipo explícita ou de ampliação.
package datatypes;
public class Main {
public static void main(String[] args) {
double number1 = 8.5;
int number2 = (int) number1;
System.out.println(number2); // 8
}
}
Você já viu que, ao tentar converter um tipo de dado maior em um menor, o compilador reclama. Mas, ao adicionar o (int)
operador de conversão explicitamente, você mostra ao compilador quem manda.
Ao fazer isso, você perde parte dos seus dados. Se alterar o double
número inicial de 8.5
para apenas 8.0
, você não perderá nenhuma informação. Portanto, sempre que realizar uma conversão explícita, tenha cuidado.
Você também pode converter a char
para an int
da seguinte maneira:
public class Main {
public static void main(String[] args) {
char character = 'F';
int number = character;
System.out.println(number); // 70
}
}
70
é o código ASCII do caractere F
– é por isso que a saída ficou assim. Se você quiser saber mais sobre códigos ASCII, meu colega Kris Koishigawa escreveu um excelente artigo sobre o assunto.
O fluxo de conversão neste caso será o oposto do que você já viu.
Sugiro que você experimente converter vários valores de um tipo para outro e veja o que acontece. Isso aprofundará sua compreensão e o deixará mais confiante.
O que são classes wrapper em Java?
Classes wrapper podem envolver tipos de dados primitivos e transformá-los em tipos de referência. Classes wrapper estão disponíveis para todos os oito tipos de dados primitivos.
Tipo primitivo | Classe Wrapper |
int |
Integer |
long |
Long |
short |
Short |
byte |
Byte |
boolean |
Boolean |
char |
Character |
float |
Float |
double |
Double |
Você pode usar essas classes wrapper da seguinte maneira:
public class Main {
public static void main (String[] args) {
Integer age = 27;
Double gpa = 4.8;
System.out.println(age); // 27
System.out.println(gpa); // 4.8
}
}
Tudo o que você precisa fazer é substituir o tipo de dado primitivo pela classe wrapper equivalente. Esses tipos de referência também possuem métodos para extrair o tipo primitivo deles.
Por exemplo, age.intValue()
retornará a idade como um inteiro primitivo e gpa.doubleValue()
retornará o GPA em um tipo double primitivo.
Existem métodos semelhantes para todos os oito tipos de dados. Embora você use os tipos primitivos na maioria das vezes, essas classes wrapper serão úteis em alguns cenários que discutiremos em uma seção posterior.
Como usar operadores em Java
Operadores em programação são certos símbolos que dizem ao compilador para executar certas operações, como operações aritméticas, relacionais ou lógicas.
Embora existam seis tipos de operadores em Java, não falarei sobre operadores bit a bit aqui. Discutir operadores bit a bit em um guia para iniciantes pode ser intimidador.
O que são operadores aritméticos?
Operadores aritméticos são aqueles que você pode usar para realizar operações aritméticas. Existem cinco deles:
OPERADOR | OPERAÇÃO |
+ |
Adição |
- |
Subtração |
* |
Multiplicação |
/ |
Divisão |
% |
Resto (Módulo/Módulo) |
As operações de adição, subtração, multiplicação e divisão são bastante autoexplicativas. Veja o exemplo de código a seguir para entender:
public class Main {
public static void main(String[] args) {
int number1 = 10;
int number2 = 5;
System.out.println(number1 + number2); // 15
System.out.println(number1 - number2); // 5
System.out.println(number1 * number2); // 50
System.out.println(number1 / number2); // 2
System.out.println(number1 % number2); // 0
}
}
As saídas das quatro primeiras operações não precisam de explicação. Na última operação, você executou uma operação módulo/módulo usando o %
símbolo. O resultado é 0
que, se você dividir 10 por 2, não sobrará nada (sem resto).
As operações de adição e multiplicação são bastante simples. Mas, ao realizar uma subtração, se o primeiro operando for maior que o segundo, o resultado será um número negativo, assim como na vida real.
O tipo de dados com o qual você está trabalhando faz diferença no resultado das operações de divisão e módulo.
public class Main {
public static void main(String[] args) {
int number1 = 8;
int number2 = 5;
System.out.println(number1 / number2); // 1
}
}
Embora o resultado dessa operação devesse ser 1,6, isso não aconteceu porque, em Java, se você dividir um inteiro por outro inteiro, o resultado será um inteiro. Mas se você transformar ambos ou um deles em um float/double, tudo voltará ao normal.
public class Main {
public static void main(String[] args) {
double number1 = 8;
double number2 = 5;
System.out.println(number1 / number2); // 1.6
}
}
Este princípio também se aplica às operações de módulo. Se ambos ou um dos operandos for um float/double, o resultado será um float/double.
O que são os operadores de atribuição?
Você já trabalhou com o operador de atribuição em uma seção anterior.
public class Main {
public static void main(String[] args) {
// =
int age = 27;
// prints the age on the terminal
System.out.println(age);
}
}
Quando você usa o =
símbolo para atribuir um valor a uma variável, ele funciona como um operador de atribuição. Mas esta não é a única forma deste operador.
Combinando o operador de atribuição regular com os operadores aritméticos, você pode obter resultados diferentes.
OPERADOR | OPERAÇÃO | EQUIVALENTE A |
+= |
a += b |
a = a + b |
-= |
a -= b |
a = a - b |
*= |
a *= b |
a = a * b |
/= |
a /= b |
a = a / b |
%= |
a %= b |
a = a % b |
O exemplo de código a seguir deve deixar as coisas mais claras:
package operators;
public class Main {
public static void main(String[] args) {
double number1 = 10;
double number2 = 5;
number1 += number2;
System.out.println(number1); // 15
}
}
Os outros operadores funcionam da mesma forma. Eles operam e atribuem o valor resultante ao operando da esquerda.
Eu poderia demonstrar os outros usando código, mas acho que se você mesmo os experimentar, entenderá melhor. Afinal, experimentação e prática são as únicas maneiras de consolidar seu conhecimento.
O que são operadores relacionais?
Operadores relacionais são usados para verificar a relação entre operandos, como, por exemplo, se um operando é igual a outro operando ou não.
Esses operadores relacionais retornam true
ou , false
dependendo da operação que você realizou.
Existem seis operadores relacionais em Java.
OPERADOR | EXPLICAÇÃO | USO |
---|---|---|
== |
É igual a | 5 == 8 retornos false |
!= |
Não é igual a | 5 != 8 retornos true |
> |
É maior que | 5 > 8 retornos false |
< |
É menor que | 5 < 8 retornos true |
>= |
Maior ou igual a | 5 >= 8 retornos false |
<= |
Menor ou igual a | 5 <= 8 retornos true |
O exemplo de código a seguir demonstra o uso desses operadores:
public class Main {
public static void main(String[] args) {
double number1 = 10;
double number2 = 5;
System.out.println(number1 == number2); // false
System.out.println(number1 != number2); // true
System.out.println(number1 > number2); // true
System.out.println(number1 < number2); // false
System.out.println(number1 >= number2); // true
System.out.println(number1 <= number2); // false
}
}
O uso prático desses operadores ficará muito mais claro para você depois que aprender sobre instruções condicionais em uma seção posterior.
Você também pode usar esses operadores com caracteres.
public class Main {
public static void main(String[] args) {
char smallLetter = 'a';
char capitalLetter = 'A';
System.out.println(smallLetter > capitalLetter); // ???
}
}
Qual você acha que será a saída deste código? Descubra você mesmo. Lembra dos valores ASCII dos caracteres? Eles desempenham um papel na saída deste programa.
O que são operadores lógicos?
Imagine um cenário em que um programa que você criou só pode ser usado por pessoas com 18 anos ou mais, mas não maiores de 40 anos. Portanto, a lógica seria a seguinte:
can run the program if ->
age >= 18 and age <= 40
Ou, em outro cenário, um usuário precisa ser aluno da sua escola ou membro da biblioteca para pegar livros emprestados. Nesse caso, a lógica seria a seguinte:
can borrow books if ->
isSchoolStudent or isLibraryMember
Essas decisões lógicas podem ser tomadas usando operadores lógicos. Existem três desses operadores em Java.
OPERADOR | USO | EXPLICAÇÃO | ||||
Lógico E ( && ) |
age >= 18 && age <= 40 |
Avalia como verdadeiro somente se ambas as condições forem verdadeiras | ||||
Lógico Ou (` | `) | `éEstudanteEscolar | éMembro da Biblioteca` | Avalia como verdadeiro se uma das duas ou ambas as condições forem verdadeiras | ||
Não ( ! ) |
!isLibraryMember |
Avalia como falso se a condição interna for avaliada como verdadeira e vice-versa |
Vamos ver esses operadores em código. Primeiro, o and
operador lógico:
public class Main {
public static void main(String[] args) {
int age = 20;
System.out.println(age >= 18 && age <= 40); // true
}
}
Neste caso, há duas condições em cada lado do &&
operador. Se, e somente se, ambas as condições forem avaliadas como true
, a and
operação será avaliada como true
.
Se a primeira condição for avaliada como false
, o computador não avaliará as demais condições e retornará false
. Porque se a primeira condição for avaliada como false
, não há como toda a operação ser avaliada como true
.
O operador lógico or
funciona de forma semelhante, mas neste caso, se qualquer uma das condições for verdadeira, toda a operação será avaliada como verdadeira:
public class Main {
public static void main(String[] args) {
boolean isSchoolStudent = true;
boolean isLibraryMember = false;
System.out.println(isSchoolStudent || isLibraryMember); // true
}
}
or
Se a primeira condição de uma operação lógica for avaliada como true
, o computador não avaliará as demais condições e retornará true
. Porque se a primeira condição for avaliada como , true
a operação será avaliada como , true
independentemente do resultado das outras condições.
Por fim, o not
operador é avaliado como o oposto do valor da sua condição. Veja o seguinte exemplo de código:
public class Main {
public static void main(String[] args) {
boolean isLibraryMember = true;
System.out.println(isLibraryMember); // true
System.out.println(!isLibraryMember); // false
}
}
Como você pode ver, o operador not retorna o oposto do boolean
valor fornecido. O operador not é um operador unário, o que significa que opera em um único operando.
public class Main {
public static void main(String[] args) {
boolean isLibraryMember = true;
boolean isSchoolStudent = false;
System.out.println(!isSchoolStudent || isLibraryMember); // true
}
}
Neste exemplo, o operador not se transforma isSchoolStudent
em true
, então a operação é avaliada como true
. No entanto, se você modificar o código da seguinte forma:
public class Main {
public static void main(String[] args) {
boolean isLibraryMember = true;
boolean isSchoolStudent = false;
System.out.println(!(isSchoolStudent || isLibraryMember)); // false
}
}
Primeiro, a operação lógica "or" será executada e avaliada como true
. O operador "not" a transformará em false
.
Embora você tenha usado dois operandos com cada operador, pode usar quantos quiser. Você também pode misturar e combinar vários operadores.
public class Main {
public static void main(String[] args) {
boolean isSchoolStudent = true;
boolean isLibraryMember = false;
int age = 10;
System.out.println(isSchoolStudent || isLibraryMember && age > 18); // ???
}
}
Qual você acha que será o resultado deste código? Recomendo que você descubra por si mesmo. :)
O que são operadores unários?
Existem alguns operadores que são usados com um operando por vez e são chamados de operadores unários. Embora existam cinco deles, discutirei apenas dois.
OPERADOR | EXPLICAÇÃO |
Incremento ( ++ ) |
Incrementa um valor fornecido em 1 |
Decremento ( -- ) |
Decrementa um valor dado em 1 |
O exemplo de código a seguir irá demonstrá-los bem:
public class Main {
public static void main(String[] args) {
int score = 95;
int turns = 11;
score++;
turns--;
System.out.println(score); // 96
System.out.println(turns); // 10
}
}
Você também pode usar os operadores como prefixos:
public class Main {
public static void main(String[] args) {
int score = 95;
int turns = 11;
++score;
--turns;
System.out.println(score); // 96
System.out.println(turns); // 10
}
}
Até aqui, tudo é simples. Mas existem algumas pequenas diferenças entre as sintaxes pós-fixada e prefixada que você precisa entender. Observe o código a seguir:
package operators;
public class Main {
public static void main(String[] args) {
int score = 95;
System.out.println(++score); // 96
System.out.println(score); // 96
}
}
Este é o comportamento esperado. O operador de decremento de prefixo funcionará da mesma forma. Mas veja o que acontece se você mudar para a versão pós-fixada:
package operators;
public class Main {
public static void main(String[] args) {
int score = 95;
System.out.println(score++); // 95
System.out.println(score); // 96
}
}
Confuso, não é? Qual você acha que é o valor real da variável agora? É 96. Deixe-me explicar.
Ao usar a sintaxe pós-fixada em uma função print, a função print encontra a variável primeiro e depois a incrementa. É por isso que a segunda linha imprime o valor recém-atualizado.
No caso da sintaxe de prefixo, a função encontra primeiro o operador de incremento e executa a operação. Em seguida, passa a imprimir o valor atualizado.
Essa pequena diferença pode te pegar desprevenido se você não tomar cuidado. Ou se tentar evitar incrementos ou decrementos em chamadas de função.
Como trabalhar com strings em Java
O String
tipo em Java é um dos tipos de referência mais usados. É uma coleção de caracteres que você pode usar para formar linhas de texto no seu programa.
Existem duas maneiras de criar novas strings em Java. A primeira é a maneira literal:
public class Main {
public static void main(String[] args) {
String name = "Farhan";
System.out.println("My name is " + name + ".");
}
}
Como você pode ver, declarar e usar String
this dessa maneira não é muito diferente de declarar os tipos primitivos em Java.
A segunda maneira de criar um novo String
é usando o new
operador.
public class Main {
public static void main(String[] args) {
// = new ()
String name = new String("Farhan");
System.out.println("My name is " + name + ".");
}
}
Este programa funcionará exatamente como o anterior, mas há uma pequena diferença entre os dois.
A JVM mantém uma parte da memória do seu computador para armazenar strings. Essa parte é chamada de pool de strings.
Sempre que você cria um novo objeto String
literalmente, a JVM primeiro verifica se ele String
já existe no pool. Se existir, a JVM o reutilizará. Caso contrário, a JVM o criará.
Por outro lado, ao usar o new
operador, a JVM sempre criará um novo String
objeto, não importa o que aconteça. O programa a seguir demonstra esse conceito claramente:
public class Main {
public static void main(String[] args) {
String literalString1 = "abc";
String literalString2 = "abc";
String objectString1 = new String("abc");
String objectString2 = new String("abc");
System.out.println(literalString1 == literalString2);
System.out.println(objectString1 == objectString2);
}
}
Como você já deve saber, o ==
operador é usado para verificar a igualdade. A saída deste programa será:
true
false
Como abc
já estava no conjunto de strings, a literalString2
variável o reutiliza. No caso das strings de objeto, no entanto, ambas são entidades diferentes.
Como formatar uma string
Você já viu o uso do +
operador para costurar strings ou formatá-las de uma maneira específica.
Essa abordagem funciona até que você tenha muitas adições a uma string. É fácil errar o posicionamento das aspas.
Uma maneira melhor de formatar uma string é o String.format()
método .
public class Main {
public static void main(String[] args) {
String name = "Farhan";
int age = 27;
String formattedString = String.format("My name is %s and I'm %d years old.", name, age);
System.out.println(formattedString);
}
}
O método recebe uma string com especificadores de formato como seu primeiro argumento e argumentos para substituir esses especificadores como argumentos posteriores.
No código acima, os caracteres %s
são %d
especificados de formato. Eles são responsáveis por informar ao compilador que esta parte da string será recuperada por algo.
Em seguida, o compilador substituirá o %s
pelo name
e %d
o pelo age
. A ordem dos especificadores precisa corresponder à ordem dos argumentos, e os argumentos precisam corresponder ao tipo do especificador.
Os especificados %s
e %d
não são aleatórios. São específicos para dados de string e números inteiros decimais. Segue uma tabela com os especificados comumente usados:
Especificador | Tipo de dados |
%b ,%B |
Booleano |
%s ,%S |
Corda |
%c ,%C |
Caractere Unicode |
%d |
Decimal Inteiro |
%f |
Números de pontos flutuantes |
Há também %o
para números inteiros octais, %x
ou %X
para números hexadecimais, e/ %e
ou %E
para notações científicas. Mas, como não os discutiremos neste livro, deixei-os de fora.
Assim como os especificadores %s
e %d
o que você viu, você pode usar qualquer um desses especificadores para o tipo de dado correspondente. E, caso você esteja perguntando, esse %f
especificador funciona tanto para floats quanto para doubles.
Como obter o comprimento de uma string ou verificar se ela está vazia ou não
Verifique o comprimento de uma string ou certifique-se de que ela não está vazia antes de executar alguma operação que seja uma tarefa comum.
Cada objeto string vem com um length()
método que retorna o comprimento dessa string. É como uma length
propriedade para arrays.
public class Main {
public static void main(String[] args) {
String name = "Farhan";
System.out.println(String.format("Length of this string is: %d.", name.length())); // 6
}
}
O método retorna o comprimento como um inteiro. Portanto, você pode usá-lo livremente em conjunto com o especificador de formato inteiro.
Para verificar se uma string está vazia ou não, você pode usar o isEmpty()
método . Assim como o length()
método, ele também vem com todos os objetos string.
public class Main {
public static void main(String[] args) {
String name = "Farhan";
if (name.isEmpty()) {
System.out.println("There is no name mentioned here");
} else {
System.out.println(String.format("Okay, I'll take care of %s.", name));
}
}
}
O método retorna um valor booleano para que você possa usá-lo diretamente nas instruções if. O programa verifica se o nome está vazio ou não e imprime respostas diferentes com base nisso.
Como dividir e unir cordas
O split()
método pode dividir uma string com base em uma expressão regular.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String name = "Farhan Hasin Chowdhury";
System.out.println(Arrays.toString(name.split(" ")));
}
}
O método retorna um array de strings. Cada string nesse array será uma substring da string original. Aqui, por exemplo, você está quebrando uma string Farhan Hasin Chowdhury
em cada espaço. Portanto, a saída será [Farhan, Hasin, Chowdhury]
.
Apenas um lembrete de que matrizes são coleções de vários dados do mesmo tipo.
Como o método recebe uma regex como argumento, você pode usar expressões regulares para executar operações de divisão mais complexas.
Você também pode unir esse array novamente em uma string como esta:
public class Main {
public static void main(String[] args) {
String name = "Farhan Hasin Chowdhury";
String substrings[] = name.split(" ");
String joinedName = String.join(" ", substrings);
System.out.println(joinedName); // Farhan Hasin Chowdhury
}
}
O join()
método também pode ajudá-lo a unir várias strings fora de um array.
public class Main {
public static void main(String[] args) {
System.out.println(String.join(" ", "Farhan", "Hasin", "Chowdhury")); // Farhan Hasin Chowdhury
}
}
Como converter uma string para autoridades ou minúsculas
Converter uma string para hierarquias ou minúsculas é muito simples em Java. Existem métodos toUpperCase()
e toLowerCase()
métodos especificamente indicados para executar as tarefas:
public class Main {
public static void main(String[] args) {
String name = "Farhan Hasin Chowdhury";
System.out.println(name.toUpperCase()); // FARHAN HASIN CHOWDHURY
System.out.println(name.toLowerCase()); // farhan hasin chowdhury
}
}
Como comparar duas strings
Como strings são tipos de referência, você não pode compará-las usando o =
operador.
O equals()
método verifica se duas strings são iguais ou não e equalsIgnoreCase()
ignora a diferenciação de características e minúsculas ao comparar.
public class Main {
public static void main(String[] args) {
String name = "Farhan Hasin Chowdhury";
String nameUpperCase = name.toUpperCase();
System.out.println(name.equals(nameUpperCase)); // false
System.out.println(name.equalsIgnoreCase(nameUpperCase)); // true
}
}
Como substituir caracteres ou substrings em uma string
O replace()
método pode substituir caracteres ou substrings inteiros de uma determinada string.
package strings;
public class Main {
public static void main(String[] args) {
String loremIpsumStd = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.";
System.out.println(String.format("Standard lorem ipsum text: %s", loremIpsumStd));
String loremIpsumHalfTranslated = loremIpsumStd.replace("Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium", "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system");
System.out.println(String.format("Translated lorem ipsum text: %s", loremIpsumHalfTranslated));
}
}
Aqui, a loremIpsumStd
string contém uma parte do texto original de Lorem Ipsum. Em seguida, você substitui a primeira linha dessa string e salva a nova string na loremIpsumHalfTranslated
variável.
Como verificar se uma string contém uma substring ou não
O contains()
método pode verificar se uma determinada string contém uma determinada substring ou não.
public class Main {
public static void main(String[] args) {
String lyric = "Roses are red, violets are blue";
if (lyric.contains("blue")) {
System.out.println("The lyric has the word blue in it.");
} else {
System.out.println("The lyric doesn't have the word blue in it.");
}
}
}
O método retorna um valor booleano, então você pode usar a função em qualquer instrução condicional.
Existem alguns dos métodos de string mais comuns. Se quiser saber mais sobre os outros, sinta-se à vontade para consultar a documentação oficial .
Quais são as diferentes maneiras de inserir e enviar dados?
Até agora, você aprendeu sobre o System.out.println()
método para imprimir informações no terminal. Você também aprendeu sobre o String.format()
método em uma seção anterior.
Nesta seção, você aprenderá sobre alguns irmãos do System.out.println()
método. Você também aprenderá sobre como receber informações do usuário.
Receber informações do usuário é extremamente fácil em linguagens como Python. No entanto, em Java, são necessárias algumas linhas de código a mais.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("What's your name? ");
String name = scanner.nextLine();
System.out.printf("So %s. How old are you? ", name);
int age = scanner.nextInt();
System.out.printf("Cool! %d is a good age to start programming.", age);
scanner.close();
}
}
A java.util.Scanner
classe é necessária para receber entradas do usuário. Você pode trazer a classe para o seu programa usando a import
palavra-chave .
Em seguida, você precisará criar uma nova instância da Scanner
classe usando a new
palavra-chave . Ao criar a nova instância, você deverá informar o fluxo de entrada desejado.
Você pode querer receber a entrada do usuário ou de um arquivo. Seja qual for, você terá que informar o compilador. O System.in
fluxo é o fluxo padrão de entrada e saída.
O objeto scanner tem métodos como nextLine()
para receber entrada de string, nextInt()
para receber entrada de inteiro, nextDouble()
para receber entrada dupla e assim por diante.
No código acima, o scanner.nextLine()
método solicitará uma string do usuário e retornará a entrada fornecida com um caractere de nova linha anexado.
O scanner.nextInt()
método então solicitará um inteiro e retornará o número fornecido pelo usuário.
Talvez você esteja vendo o System.out.printf()
método pela primeira vez aqui. Bem, além do System.out.println()
método, há também o System.out.print()
método que imprime uma string específica sem adicionar um caractere de quebra de linha a ela.
É System.out.printf()
uma espécie de combinação dos métodos System.out.print()
e String.format()
. Você também pode usar os especificadores de formato discutidos anteriormente neste método.
Após terminar de receber a entrada, você precisará fechar o objeto scanner. Para isso, basta chamar o scanner.close()
método .
Simples, não é? Vou complicar um pouco.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("What's your name? ");
String name = scanner.nextLine();
System.out.printf("So %s. How old are you? ", name);
int age = scanner.nextInt();
System.out.printf("Cool! %d is a good age to start programming.
What language would you prefer? ", age);
String language = scanner.nextLine();
System.out.printf("Ah! %s is a solid programming language.", language);
scanner.close();
}
}
Adicionei uma nova scanner.nextLine()
instrução após a scanner.nextInt()
chamada do método. Vai funcionar?
Não, não vai. O programa simplesmente pulará o último prompt de entrada e imprimirá a última linha. Esse comportamento não é exclusivo de scanner.nextInt()
. Se você usar scanner.nextLine()
depois de qualquer um dos outros nextWhatever()
métodos, enfrentará esse problema.
Resumindo, isso acontece porque quando você pressiona enter no scanner.nextInt()
método, ele consome o inteiro e deixa o caractere de nova linha no buffer de entrada.
Portanto, quando scanner.nextLine()
é invocado, ele consome esse caractere de nova linha como o fim da entrada. A solução mais fácil para esse problema é escrever uma scanner.nextLine()
chamada adicional após as outras chamadas do método do scanner.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("What's your name? ");
String name = scanner.nextLine();
System.out.printf("So %s. How old are you? ", name);
int age = scanner.nextInt();
// consumes the dangling newline character
scanner.nextLine();
System.out.printf("Cool! %d is a good age to start programming.
What language would you prefer? ", age);
String language = scanner.nextLine();
System.out.printf("Ah! %s is a solid programming language.", language);
scanner.close();
}
}
Existe outra maneira de resolver este problema. Mas não vou entrar em detalhes aqui. Se tiver interesse, confira meu artigo sobre o assunto .
Como usar instruções condicionais em Java
Use instruções condicionais para tomar decisões com base em condições.
Isso é feito usando a if
instrução a seguir:
public class Main {
public static void main(String[] args) {
int age = 20;
// if (condition) {...}
if (age >= 18 && age <= 40) {
System.out.println("you can use the program");
}
}
}
A instrução começa com um if
e, em seguida, há a condição dentro de um par de parênteses. Se a condição for avaliada como verdadeira, o código entre chaves será executado.
O código entre chaves é conhecido como bloco de código.
Se você alterar o valor de age
para , 50
a instrução print não será executada e não haverá saída no console. Para esses tipos de situações em que a condição é avaliada como false
, você pode adicionar um else
bloco:
public class Main {
public static void main(String[] args) {
int age = 20;
if (age >= 18 && age <= 40) {
System.out.println("you can use the program");
} else {
System.out.println("you can not use the program");
}
}
}
Agora, se a condição for avaliada como false
, o código dentro do else
bloco será executado e você verá you can not use the program
impresso no seu terminal.
Você também pode ter várias condições dentro de uma if-else if-else
escada:
public class Main {
public static void main(String[] args) {
int age = 50;
boolean isSchoolStudent = true;
boolean isLibraryMember = false;
// if (condition) {...}
if (age >= 18 && age <= 40) {
System.out.println("you can use the program");
} else if (isSchoolStudent || isLibraryMember) {
System.out.println("you can use the program for a short time");
} else {
System.out.println("you can not use the program");
}
}
}
Agora, se a primeira condição for avaliada como false
, a segunda condição será testada. Se a segunda condição for avaliada como , true
o código entre chaves será executado. Se as condições em ambas if
as instruções forem avaliadas como false
, o else
bloco será executado.
Você também pode aninhar if
instruções dentro de outras if
instruções da seguinte maneira:
package operators;
public class Main {
public static void main(String[] args) {
int age = 20;
if (age >= 18 && age <= 40) {
boolean isSchoolStudent = true;
boolean isLibraryMember = false;
if (isSchoolStudent || isLibraryMember) {
System.out.println("you can use the program");
}
} else {
System.out.println("you can not use the program");
}
}
}
Nesse caso, if
a declaração interna será testada somente se a primeira declaração for avaliada como verdadeira if
.
O que é uma instrução switch-case?
Além dos blocos if-else, também existem casos de switch onde você pode definir vários casos com base em um único switch.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("What is the first operand? ");
int a =scanner.nextInt();
// consumes the dangling newline character
scanner.nextLine();
System.out.print("What is the second operand? ");
int b = scanner.nextInt();
// consumes the dangling newline character
scanner.nextLine();
System.out.print("What operation would you like to perform? ");
String operation = scanner.nextLine();
switch (operation) {
case "sum":
System.out.printf("%d + %d = %d", a, b, a+b);
break;
case "sub":
System.out.printf("%d - %d = %d", a, b, a-b);
break;
case "mul":
System.out.printf("%d * %d = %d", a, b, a*b);
break;
case "div":
if (b == 0) {
System.out.print("Can't divide by zero!");
} else {
System.out.printf("%d / %d = %d", a, b, a / b);
}
break;
default:
System.out.printf("Invalid Operation!");
}
scanner.close();
}
}
Este é um programa de calculadora muito simples. O programa solicita ao usuário dois números e, em seguida, pergunta qual operação ele gostaria de realizar.
Cada instrução switch-case terá um switch e vários cases. Quando você diz case "sum"
, o programa verifica se o valor do switch ou da operation
variável em this é válido sum
ou não.
Se houver correspondência, o corpo do caso será executado. Se nenhum dos casos corresponder, o default
caso será executado.
E sobre essa break
afirmação. Ela faz o que parece: impede o programa de avançar para o próximo caso.
Se você remover as break
instruções, todos os casos serão executados um após o outro até que o default
caso seja alcançado.
O que é escopo de variável em Java?
Escopo é o tempo de vida e a acessibilidade de uma variável. Dependendo de onde você declara uma variável, você pode ou não conseguir acessá-la de outros lugares.
Veja o seguinte trecho de código como exemplo:
public class Main {
public static void main(String[] args) {
int age = 20;
if (age >= 18 && age <= 40) {
// age variable is accessible here
// booleans are not accessible here
boolean isSchoolStudent = true;
boolean isLibraryMember = false;
if (isSchoolStudent || isLibraryMember) {
// booleans are accessible here
// age variable is accessible here
System.out.println("you can use the program");
}
} else {
// age variable is accessible here
// booleans are not accessible here
System.out.println("you can not use the program");
}
}
}
Aqui, a age
variável é declarada dentro do class
bloco de código. Isso significa que você pode acessá-la dentro de toda a classe sem problemas. Como a variável é acessível em toda a instância da classe, ela é uma variável de instância.
No entanto, as variáveis isSchoolStudent
e isLibraryMember
foram declaradas dentro do primeiro if
bloco de código de instrução. Portanto, elas não serão acessíveis fora desse bloco de código.
Mas ele estará acessível em qualquer bloco de código aninhado dentro do primeiro if
bloco. Essas são chamadas de variáveis locais.
Há também variáveis de classe declaradas usando a static
palavra-chave, mas você aprenderá sobre elas nas seções de programação orientada a objetos.
Então, por enquanto, a regra geral é que uma variável estará acessível dentro do bloco de código em que foi declarada e qualquer outro bloco de código aninhado dentro do bloco pai.
Quais são os valores padrões das variáveis em Java?
Você aprendeu que em Java é preciso inicializar uma variável depois de declará-la. Caso contrário, você não conseguirá usar isso. Bem, isso não é verdade em todos os casos.
Se você declarar uma variável no nível de classe, essa variável receberá um valor padrão do compilador.
public class Main {
// gets 0 as the value by default
static int age;
public static void main(String[] args) {
System.out.println(age); // 0
}
}
Como o main
método é static
, ele só pode acessar static
variáveis no nível de classe. Discutirei isso static
com mais detalhes na seção de programação orientada a objetos.
Mas se você mover a declaração da variável dentro do main
método, ela se torna local para esse método e não recebe nenhum valor padrão.
public class Main {
public static void main(String[] args) {
// remains uninitialized
int age;
System.out.println(age); // fails to compile
}
}
Este código gerará o The local variable age may not have been initialized
erro na compilação.
As variáveis recebem seus valores padrão com base em seu tipo. Na maioria dos casos, será 0
ou null
. Estou listando todos os tipos primitivos e seus valores padrão:
Tipo de dados | Valor padrão |
byte |
0 |
short |
0 |
int |
0 |
long |
0L |
float |
0.0f |
double |
0.0d |
char |
'u0000' |
boolean |
false |
Qualquer tipo de referência receberá o valor null
por padrão. Discutiremos tipos de referência, classes e objetos nas seções de programação orientada a objetos.
Como trabalhar com matrizes em Java
Você já aprendeu a declarar variáveis únicas e usá-las no seu programa. É aqui que entram os arrays.
Matrizes são estruturas de dados que contêm múltiplos valores do mesmo tipo de dado em memórias sequenciais. Matrizes podem ser de qualquer tipo de dado primitivo ou não primitivo.
Você pode criar um array em Java da seguinte maneira:
public class Main {
public static void main(String[] args) {
// [] = new []
char vowels[] = new char[5];
}
}
Neste caso , comece digitando o tipo de dado que deseja armazenar no array char
. Em seguida, escreva o nome do array, vowels
seguido por um par de colchetes. Este par de colchetes indica ao Java que você está declarando um array de caracteres e não uma variável de caractere comum.
Em seguida, insira um sinal de igual seguido do new
operador usado para criar novos objetos em Java. Como arrays são tipos de referência em Java, new
é necessário para criar novas instâncias.
Finalize a declaração escrevendo o tipo novamente, seguido por outro par de colchetes delimitando o comprimento do array. Aqui, 5
significa que o array conterá cinco elementos e não mais que isso.
Ao trabalhar com uma única variável, você pode se referir a ela simplesmente pelo seu nome. Mas, no caso de um array, cada elemento terá um índice e os arrays são baseados em zero. Isso significa que o primeiro elemento em um array terá 0
como índice e não 1
.
Para acessar um elemento em um array, comece escrevendo o nome do array – neste caso, vowels
seguido por um par de colchetes envolvendo o índice desejado. Portanto, se quiser acessar o primeiro elemento do array, faça o seguinte:
public class Main {
public static void main(String[] args) {
char vowels[] = new char[5];
vowels[0] = 'a';
}
}
Neste ponto, vowels[0]
é semelhante a uma variável de caractere comum. Você pode imprimi-la, atribuir um novo valor a ela, realizar cálculos no caso de tipos numéricos e assim por diante.
Como o array está vazio neste momento, estou atribuindo o caractere a
ao primeiro índice. Você pode atribuir o restante das vogais aos demais índices da seguinte maneira:
public class Main {
public static void main(String[] args) {
char vowels[] = new char[5];
vowels[0] = 'a';
vowels[1] = 'e';
vowels[2] = 'i';
vowels[3] = 'o';
vowels[4] = 'u';
}
}
Como os índices começam em , 0
eles terminam no comprimento do array - 1, que neste caso é 4
. Se você tentar atribuir outro elemento ao array, vowels[4] = 'x';
o compilador gerará o seguinte erro:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at arrays.Main.main(Main.java:18)
Matrizes não podem ser impressas como variáveis comuns. Você terá que usar um laço (loop) ou converter a matriz em uma string. Como ainda não discuti laços (loops), usarei o segundo método.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = new char[5];
vowels[0] = 'a';
vowels[1] = 'e';
vowels[2] = 'i';
vowels[3] = 'o';
vowels[4] = 'u';
System.out.println("These are the vowels: " + Arrays.toString(vowels));
}
}
Primeiro, você precisará importar java.util.Arrays;
e usar o Arrays.toString()
método para converter o array em uma string. Esta classe possui vários outros métodos interessantes, mas antes de discuti-los, gostaria de mostrar como declarar e inicializar um array de uma só vez.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
System.out.println("These are the vowels: " + Arrays.toString(vowels));
}
}
O lado esquerdo da sintaxe da declaração permanece inalterado. No entanto, após o operador de atribuição, em vez de usar, new
você escreve os elementos individuais do array separados por vírgula e entre chaves.
Nesse caso, o compilador contará o número de elementos no array e usará isso como o comprimento do array.
Se você não sabe o comprimento de um array, você pode dar uma olhada na length
propriedade.
Neste caso, vowels.length
será, 5
pois há cinco elementos no array. A length
propriedade é um inteiro e está presente em todos os arrays em Java.
Matrizes também podem ser multidimensionais. Até agora, você trabalhou com matrizes como esta:
Matrizes unidimensionais como esta são perfeitas quando você deseja armazenar uma série de valores. Mas imagine a rotina médica diária de alguém na forma de uma tabela:
A primeira linha representa os sete dias da semana e as colunas representam quantas vezes o paciente deve tomar o medicamento, das três vezes ao dia. 0
significa não e 1
significa sim.
Você pode mapear essa rotina usando uma matriz multidimensional em seu programa:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int medicineRoutine[][] = {
{1, 2, 3, 4, 5, 6, 7},
{0, 1, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 0},
{0, 0, 1, 1, 0, 1, 0},
};
System.out.println(Arrays.deepToString(medicineRoutine)); // [[1, 2, 3, 4, 5, 6, 7], [0, 1, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 0, 0], [0, 0, 1, 1, 0, 1, 0]]
}
}
Matrizes multidimensionais não podem ser impressas usando o Arrays.toString()
método regular; você precisa pesquisar mais a fundo.
Embora a saída não se pareça em nada com a tabela, você pode fazer com que ela pareça uma tabela usando alguma programação inteligente:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int medicineRoutine[][] = {
{1, 2, 3, 4, 5, 6, 7},
{0, 1, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 0},
{0, 0, 1, 1, 0, 1, 0},
};
System.out.println(Arrays.deepToString(medicineRoutine).replace("], ", "]
"));
}
}
// [[1, 2, 3, 4, 5, 6, 7]
// [0, 1, 1, 0, 1, 1, 0]
// [1, 0, 1, 0, 1, 0, 0]
// [0, 0, 1, 1, 0, 1, 0]]
Você já aprendeu sobre o replace()
método para strings. Você está apenas substituindo a chaveta final em cada linha por uma chaveta e um caractere de nova linha.
A primeira linha representa os 7 dias da semana e as demais linhas são as rotinas médicas de cada dia. Cada linha nesta tabela representa uma matriz.
Para acessar um único valor de uma matriz multidimensional, você precisará de dois índices. O primeiro índice determina a linha e o segundo determina a coluna.
Então medicineRoutine[2][3]
, selecionaremos o elemento no índice 3
do terceiro array. Esse elemento será 0
. Trabalhar com arrays multidimensionais pode parecer um pouco complicado, mas praticar tornará isso muito mais fácil.
Já que você pode criar arrays de qualquer tipo em Java, por que não tenta criar outros tipos de arrays você mesmo?
Como classificar uma matriz
Uma das tarefas mais comuns que você executará em arrays é classificá-los. java.utils.Arrays
O Arrays.sort()
método para fazer exatamente isso é:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = {'e', 'u', 'o', 'i', 'a'};
Arrays.sort(vowels);
System.out.println("The sorted array: " + Arrays.toString(vowels)); // [a, e, i, o , u]
}
}
O Arrays.sort()
método recebe o array não classificado como argumento e o classifica no local. Assim, em vez de receber um novo array classificado como retorno, o array original será classificado em ordem crescente.
Por padrão, o método trata o primeiro índice do array como seu índice inicial e o comprimento do array como seu índice final.
Você pode especificar esses dois índices manualmente. Por exemplo, se quiser classificar apenas u, o, i
em ordem crescente e deixar e, a
como está, faça o seguinte:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = {'e', 'u', 'o', 'i', 'a'};
int startIndex = 1;
int endIndex = 4;
Arrays.sort(vowels, startIndex, endIndex);
System.out.println("The sorted array: " + Arrays.toString(vowels)); // [e, i, o, u , a]
}
}
Desta vez, o método usa o array como primeiro parâmetro, o índice inicial como segundo parâmetro e o índice final como terceiro parâmetro. O restante dos comportamentos permanece o mesmo de antes.
Como realizar uma pesquisa binária em uma matriz
Pesquisar valores dentro de um valor ordenado é outra tarefa comum. O Arrays.binarySearch()
método permite pesquisar itens em uma matriz ordenada usando o algoritmo de busca binária.
public class Main {
public static void main(String[] args) {
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
char key = 'i';
int foundItemIndex = Arrays.binarySearch(vowels, key);
System.out.println("The vowel 'i' is at index: " + foundItemIndex); // 2
}
}
O Arrays.binarySearch()
método recebe um array como primeiro parâmetro e a chave de busca (também conhecida como o item que você está procurando) como segundo parâmetro. Ele retornará o índice do item encontrado como um inteiro.
Você pode armazenar esse índice em um int
e usá-lo para acessar o elemento do array como vowels[foundItemIndex]
.
Observe que o array precisa ser ordenado em ordem crescente. Se não tiver certeza da ordem do array, use o Arrays.sort()
método para ordená-lo primeiro.
Por padrão, o método trata o primeiro índice do array como seu índice inicial e o comprimento do array como seu índice final. Mas você também pode especificar esses índices manualmente.
Por exemplo, se você quiser que a pesquisa ocorra de índice 2
para índice 4
, você pode fazer isso da seguinte maneira:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = {'a', 'e', 'i', 'o', 'u'};
char key = 'i';
int startIndex = 2;
int endIndex = 4;
int foundItemIndex = Arrays.binarySearch(vowels, startIndex, endIndex, key);
System.out.println("The vowel 'i' is at index: " + foundItemIndex); // 2
}
}
Desta vez, o método usa o array que você deseja pesquisar como o primeiro parâmetro, o índice inicial como o segundo parâmetro, o índice final como o terceiro parâmetro e a chave de pesquisa como o quarto parâmetro.
Agora, a busca ocorrerá em i
, o
e u
. Portanto, se você procurar por a
, ele não será encontrado. Caso o item fornecido não seja encontrado, você obterá um índice negativo. O índice negativo resultante variará com base em uma série de fatores, mas não entrarei em detalhes aqui. Se você tiver interesse em saber mais, confira meu artigo sobre o assunto .
Como preencher uma matriz
Você já aprendeu a inicializar um array com valores, mas às vezes pode ser necessário preencher um array inteiro com o mesmo valor. O Arrays.fill()
método pode fazer isso por você:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = {'e', 'u', 'o', 'i', 'a'};
Arrays.fill(vowels, 'x');
System.out.println("The filled array: " + Arrays.toString(vowels)); // [x, x, x, x, x]
}
}
Assim como o Arrays.sort()
método, Arrays.fill()
ele também executa sua operação no local. Ele recebe seu array como primeiro parâmetro, o valor com o qual você deseja preencher o array como segundo parâmetro e atualiza o array original no local.
Este método também trata o primeiro índice como o índice inicial e o comprimento do array como o índice final. Você pode especificar esses índices manualmente da seguinte maneira:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
char vowels[] = {'e', 'u', 'o', 'i', 'a'};
int startIndex = 1;
int endIndex = 4;
Arrays.fill(vowels, startIndex, endIndex, 'x');
System.out.println("The filled array: " + Arrays.toString(vowels)); // [e, x, x, x, a]
}
}
Desta vez, o método usa seu array como o primeiro argumento, o índice inicial como o segundo argumento, o índice final como o terceiro argumento e o preenchimento como o quarto argumento.
Como fazer cópias de um array
Como os arrays em Java são de tipos de referência, copiá-los usando o operador de atribuição pode causar algum comportamento inesperado.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int oddNumbers[] = {1, 3, 5};
int copyOfOddNumbers[] = oddNumbers;
Arrays.fill(oddNumbers, 0);
System.out.println("The copied array: " + Arrays.toString(copyOfOddNumbers)); // [0, 0, 0]
}
}
Embora você tenha feito alterações no array de origem, a cópia também as reflete. Isso acontece porque, quando você usa o operador de atribuição para copiar um array, a cópia faz referência ao array original na memória.
Para copiar corretamente um array, você pode usar o Arrays.copyOf()
método da seguinte maneira:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int oddNumbers[] = {1, 3, 5};
int copyOfOddNumbers[] = Arrays.copyOf(oddNumbers, oddNumbers.length);
Arrays.fill(oddNumbers, 0);
System.out.println("The copied array: " + Arrays.toString(copyOfOddNumbers)); // [1, 3, 5]
}
}
O método recebe o array de origem como primeiro argumento e o comprimento desejado do novo array como segundo argumento. Se você quiser que o comprimento seja o mesmo, basta passar o comprimento do array original usando a length
propriedade .
Se você colocar um comprimento menor, qualquer valor depois dele será cortado e se você colocar um comprimento maior, os novos índices serão preenchidos com o valor padrão do tipo de dado da matriz.
Existe outro método Arrays.copyOfRange()
que pode copiar uma parte de uma matriz para uma nova:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int oddNumbers[] = {1, 3, 5, 7, 9, 11, 13, 15};
int startIndex = 2;
int endIndex = 7;
int copyOfOddNumbers[] = Arrays.copyOfRange(oddNumbers, startIndex, endIndex);
System.out.println("The copied array: " + Arrays.toString(copyOfOddNumbers)); // [5, 7, 9, 11, 13]
}
}
Este método usa o array de origem como seu primeiro argumento, depois o índice inicial e, finalmente, o índice final.
Lembre-se de que o índice final não é inclusivo. É por isso que 15 está ausente no novo array. Mas se você quiser incluir o último índice do array, use o comprimento do array original como índice final.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int oddNumbers[] = {1, 3, 5, 7, 9, 11, 13, 15};
int startIndex = 2;
int endIndex = oddNumbers.length;
int copyOfOddNumbers[] = Arrays.copyOfRange(oddNumbers, startIndex, endIndex);
System.out.println("The copied array: " + Arrays.toString(copyOfOddNumbers)); // [5, 7, 9, 11, 13, 15]
}
}
Agora, o novo array também incluirá 15. Você também pode inserir um número maior que o comprimento do array de origem. Nesse caso, os índices recém-adicionados conterão o valor padrão do tipo de dado do array.
Como comparar dois arrays
Se você tentar verificar se dois arrays são iguais ou não em Java usando o operador relacional equal, você obterá alguns resultados inesperados.
public class Main {
public static void main(String[] args) {
int oddNumbers1[] = {1, 3, 5, 7, 9, 11, 13, 15};
int oddNumbers2[] = {1, 3, 5, 7, 9, 11, 13, 15};
System.out.println(oddNumbers1 == oddNumbers2); // false
}
}
Embora os dois arrays sejam idênticos, a saída do programa é false
. Como arrays são tipos de referência, o operador relacional verificará se são a mesma instância ou não.
Para comparar dois arrays em Java, você pode usar o Arrays.equals()
método:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int oddNumbers1[] = {1, 3, 5, 7, 9, 11, 13, 15};
int oddNumbers2[] = {1, 3, 5, 7, 9, 11, 13, 15};
System.out.println(Arrays.equals(oddNumbers1, oddNumbers2)); // true
}
}
Entretanto, se você alterar apenas um elemento em qualquer uma dessas matrizes, a saída será, false
pois as matrizes não permanecerão mais idênticas.
Você também pode comparar matrizes multidimensionais, mas para isso você terá que usar o Arrays.deepEquals()
método em vez do método normal.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int medicineRoutine[][] = {
{1, 2, 3, 4, 5, 6, 7},
{0, 1, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 0},
{0, 0, 1, 1, 0, 1, 0},
};
int medicineRoutine2[][] = {
{1, 2, 3, 4, 5, 6, 7},
{0, 1, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0, 0},
{0, 0, 1, 1, 0, 1, 0},
};
System.out.println(Arrays.deepEquals(medicineRoutine, medicineRoutine2)); // true
}
}
Este método chama a si mesmo sempre que encontra um novo array dentro do array pai.
Esses foram alguns dos métodos mais comuns dentro da java.util.Arrays
classe. Você pode consultar a documentação oficial se quiser saber mais.
Como usar loops em Java
Se precisar repetir uma tarefa por um determinado número de vezes, você pode usar um loop. Os loops podem ser de três tipos: loops for
, for...each
loops e while
loops.
Para Laço
Os loops for são provavelmente os tipos mais comuns de loops que você verá na internet.
Cada loop for consiste em três partes: a inicialização, a condição e a expressão de atualização. O loop ocorre em várias etapas.
Se você quiser imprimir os números de 0 a 10 usando um loop for, você pode fazer isso da seguinte maneira:
public class Main {
public static void main(String[] args) {
for (int number = 0; number <= 10; number++) {
System.out.println(number);
}
}
}
// 0
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
O fluxograma desse loop se parece com isso:
- No início do loop, você inicializa um novo inteiro nomeado
number
com o valor inicial de0
. - Então você verifica se o
number
é menor ou igual a10
ou não. - Se for menor ou igual a
10
, você executa a instrução dentro do bloco de loop e imprime o número no terminal. - Em seguida, você atualiza a variável numérica incrementando seu valor em 1.
- O loop retorna para verificar se o valor do número ainda é menor ou igual ou não.
Enquanto o valor de number permanecer menor ou igual a 10, o loop continua. No momento em que o valor da number
variável se torna 11
, o loop termina.
Você pode usar um loop for para percorrer um array da seguinte maneira:
public class Main {
public static void main(String[] args) {
int fibonacciNumbers[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55};
for(int index = 0; index < fibonacciNumbers.length; index++) {
System.out.println(fibonacciNumbers[index]);
}
}
}
O fluxograma para esse loop será o seguinte:
Como o último índice do array é uma unidade a menos que seu comprimento, você executa o loop enquanto o índice for menor que o comprimento do array. No momento em que o índice se torna igual ao comprimento do array, você sai do loop.
Uma das coisas divertidas que você pode fazer com laços é imprimir tabuadas de multiplicação. Por exemplo, a tabuada de multiplicação para 5 será a seguinte:
public class Main {
public static void main(String[] args) {
int number = 5;
for (int multiplier = 1; multiplier <= 10; multiplier++) {
System.out.println(String.format("%d x %d = %d", number, multiplier, number * multiplier));
}
}
}
// 5 x 1 = 5
// 5 x 2 = 10
// 5 x 3 = 15
// 5 x 4 = 20
// 5 x 5 = 25
// 5 x 6 = 30
// 5 x 7 = 35
// 5 x 8 = 40
// 5 x 9 = 45
// 5 x 10 = 50
Os laços também podem ser aninhados. Isso significa que você pode colocar um laço dentro de outro. Você pode imprimir a tabuada de todos os números de 1 a 10 usando laços aninhados:
public class Main {
public static void main(String[] args) {
for (int number = 1; number <= 10; number++) {
System.out.println(String.format("
multiplication table of %d", number));
for (int multiplier = 1; multiplier <= 10; multiplier++) {
System.out.println(String.format("%d x %d = %d", number, multiplier, number * multiplier));
}
}
}
}
Eu não ousaria imprimir a saída aqui. Em vez disso, experimente o código você mesmo. Desenhe cada iteração do loop em um pedaço de papel para entender o que está acontecendo em cada etapa.
Loop para cada
Se você quiser iterar sobre uma coleção, como uma matriz, e executar alguma operação em cada elemento dessa coleção, você pode usar um loop for...each.
public class Main {
public static void main(String[] args) {
int fibonacciNumbers[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55};
for(int number : fibonacciNumbers) {
System.out.println(number);
}
}
}
No caso de um loop for-each, o tipo de item precisa específico ao tipo da coleção com a qual você está trabalhando. Aqui, o array é do tipo inteiro, então o item no loop é do tipo inteiro.
Isso executa a mesma tarefa que o loop for mostrado anteriormente. Mas, neste caso, você não precisa controlar o índice nem usar colchetes para acessar os elementos. Parece mais limpo e menos sujeito a erros.
Enquanto Laço
Se você quiser executar um monte de código até que uma determinada condição seja atendida, você pode usar um loop while.
Não há etapas de inicialização ou atualização em um loop while. O que quer que aconteça, acontece dentro do corpo do loop. Se você reescrever o programa para imprimir a tabuada de 5 usando um loop while, ficará assim:
public class Main {
public static void main(String[] args) {
int number = 5;
int multiplier = 1;
while (multiplier <= 10) {
System.out.println(String.format("%d x %d = %d", number, multiplier, number*multiplier));
multiplier++;
}
}
}
// 5 x 1 = 5
// 5 x 2 = 10
// 5 x 3 = 15
// 5 x 4 = 20
// 5 x 5 = 25
// 5 x 6 = 30
// 5 x 7 = 35
// 5 x 8 = 40
// 5 x 9 = 45
// 5 x 10 = 50
Embora os loops while não sejam tão comuns quanto os loops para o mundo real, vale a pena aprender sobre eles.
Laço Do-While
O último tipo de loop que você aprenderá é o do-while. Ele meio que inverte a ordem do loop enquanto normal – então, em vez de verificar a condição antes de executar o corpo do loop, você executa o corpo do loop primeiro e depois verifica a condição.
O código da tabuada de multiplicação implementada usando um loop do-while será o seguinte:
public class Main {
public static void main(String[] args) {
int number = 5;
int multiplier = 1;
do {
System.out.println(String.format("%d x %d = %d", number, multiplier, number*multiplier));
multiplier++;
} while (multiplier <= 10);
}
}
// 5 x 1 = 5
// 5 x 2 = 10
// 5 x 3 = 15
// 5 x 4 = 20
// 5 x 5 = 25
// 5 x 6 = 30
// 5 x 7 = 35
// 5 x 8 = 40
// 5 x 9 = 45
// 5 x 10 = 50
Laços do tipo "do-while" são muito úteis quando você precisa executar alguma operação até que o usuário insira uma entrada específica. Por exemplo, exiba um menu até que o usuário pressione a tecla "x".
Como trabalhar com listas de array em Java
Arrays em Java não são redimensionáveis. Depois de definir um comprimento para uma matriz, você não poderá alterá-lo de alguma forma. A ArrayList
classe em Java atenua essas limitações.
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.toString()); // [1, 3, 5, 7, 9]
}
}
Para criar listas de matrizes, você precisará importar uma java.util.ArrayList
classe no topo do seu arquivo de origem.
Em seguida, comece a escrever ArrayList
e, dentro de um par de sinais de menor que-maior, escreva o tipo de dado dos elementos. Em seguida, adicione o nome da própria lista de arrays, seguido pelo operador de atribuição e new ArrayList<>()
.
Você não pode criar listas de arrays de tipos primitivos, então você terá que usar um wrapper de classe correspondente.
Embora esses elementos tenham índices de base zero, como matrizes, você não pode usar a notação de chaves quadradas para acessá-los. Em vez disso, você terá que usar o get()
método:
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.get(2)); // 5
}
}
O get()
método fornecerá o valor no índice fornecido. Assim como get()
você pode usar o set()
método para atualizar o valor de um elemento.
import java.time.LocalDate;
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
oddNumbers.set(2, 55);
System.out.println(oddNumbers.get(2)); // 55
}
}
O primeiro parâmetro do set()
método é o índice e o segundo é o valor atualizado.
Não há nenhuma length
propriedade como em um array, mas você pode usar o size()
método em qualquer lista de arrays para descobrir seu comprimento.
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.size()); // 5
}
}
Você pode remover elementos de uma lista de matriz usando o método remove:
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
oddNumbers.remove(Integer.valueOf(7));
oddNumbers.remove(Integer.valueOf(9));
System.out.println(oddNumbers.toString()); // [1, 3, 5]
}
}
O remove()
método pode remover um elemento por valor ou por índice. Se você passar um valor inteiro primitivo para o método, ele removerá o elemento não fornecido.
Mas se você passar um objeto como este código, o método encontrará e excluirá o elemento fornecido. O valueOf()
método está presente em todas as classes wrapper e pode converter um valor primitivo em um tipo de referência.
Como adicionar ou remover vários elementos
Você já viu exemplos de métodos add()
e remove()
. Existem dois outros métodos addAll()
e removeAll()
para trabalhar com múltiplos elementos.
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
ArrayList<Integer> moreOddNumbers = new ArrayList<>();
moreOddNumbers.add(7);
moreOddNumbers.add(9);
moreOddNumbers.add(11);
oddNumbers.addAll(moreOddNumbers); // [1, 3, 5, 7, 9, 11]
System.out.println(oddNumbers.toString());
oddNumbers.removeAll(moreOddNumbers);
System.out.println(oddNumbers.toString()); // [1, 3, 5]
}
}
Ambos os métodos aceitam coleções como parâmetro. No código acima, você está criando duas listas de arrays separadas e unindo-as usando o addAll()
método .
Em seguida, você remove os elementos da segunda lista de arrays usando o removeAll()
método e a lista de arrays retorna ao seu estado original.
Você também pode remover todos os elementos de uma lista de matriz usando o clear()
método:
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.clear();
System.out.println(oddNumbers.toString()); // []
}
}
O método não requer nenhum parâmetro e também não retorna nenhum valor. Ele apenas esvazia sua lista de arrays em uma única chamada.
Como remover elementos com base em uma condição
O removeIf()
método pode remover elementos de uma lista de matrizes se eles atenderem a uma determinada condição:
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> numbers = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
numbers.add(i);
}
System.out.println(numbers.toString()); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.removeIf(number -> number % 2 == 1);
System.out.println(numbers.toString()); // [0, 2, 4, 6, 8, 10]
}
}
O método recebe uma expressão lambda como parâmetro. Expressões lambda são como métodos sem nome. Eles podem receber parâmetros e trabalhar com eles.
Aqui, o removeIf()
método percorrerá uma lista de arrays e passará cada elemento para a expressão lambda como o valor da number
variável.
Então a expressão lambda verificará se o número fornecido é divisível por 2 ou não será retornado true
ou false
com base nisso.
Se a expressão lambda retornar true
, o removeIf()
método manterá o valor. Caso contrário, o valor será excluído.
Como clonar e comparar listas de array
Para fazer uma duplicata de uma lista de matrizes, você pode usar o clone()
método .
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> numbers = new ArrayList<>();
for (int i = 0; i <= 10; i++) {
numbers.add(i);
}
ArrayList<Integer> numbersCloned = (ArrayList<Integer>)numbers.clone();
System.out.println(numbersCloned.equals(numbers)); // true
}
}
O clone()
método retorna um objeto, então você terá que convertê-lo manualmente para uma lista de arrays adequada. Você pode comparar duas listas de arrays usando o equals()
método, assim como em arrays.
Como verificar se um elemento está presente ou se a lista de matrizes está vazia
Você pode usar o contains()
método para verificar se uma lista de array contém um determinado elemento ou não:
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
System.out.println(oddNumbers.isEmpty()); // false
System.out.println(oddNumbers.contains(5)); // true
}
}
Se você quiser verificar se uma lista de arrays está vazia ou não, basta chamar o isEmpty()
método nela e você receberá um booleano em retorno.
Como classificar uma lista de matriz
Você pode classificar uma lista de matrizes em ordens diferentes usando o sort()
método:
import java.util.ArrayList;
import java.util.Comparator;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(1);
oddNumbers.add(9);
oddNumbers.add(3);
System.out.println(oddNumbers.toString()); [5, 7, 1, 9, 3]
oddNumbers.sort(Comparator.naturalOrder());
System.out.println(oddNumbers.toString()); [1, 3, 5, 7, 9]
}
}
O sort()
método recebe um comparador como parâmetro. Um comparador impõe a ordem de classificação na lista do array.
Você pode classificar a lista de arrays na ordem reversa apenas alterando o comparador passado:
import java.util.ArrayList;
import java.util.Comparator;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(1);
oddNumbers.add(9);
oddNumbers.add(3);
System.out.println(oddNumbers.toString()); // [5, 7, 1, 9, 3]
oddNumbers.sort(Comparator.reverseOrder());
System.out.println(oddNumbers.toString()); // [9, 7, 5, 3, 1]
}
}
Os comparadores também têm outros usos, mas eles estão fora do escopo deste livro.
Como manter elementos comuns de duas listas de array
Imagine um cenário em que você tem duas listas de arrays. Agora você precisa descobrir quais elementos estão presentes em ambas as listas e remover o restante da primeira lista.
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
ArrayList<Integer> moreOddNumbers = new ArrayList<Integer>();
moreOddNumbers.add(5);
moreOddNumbers.add(7);
moreOddNumbers.add(9);
oddNumbers.retainAll(moreOddNumbers);
System.out.println(oddNumbers.toString()); // [5]
}
}
O retainAll()
método pode remover os elementos incomuns da primeira lista de arrays para você. Você precisará chamar o método na lista de arrays na qual deseja operar e passar a segunda lista de arrays como parâmetro.
Como executar uma ação em todos os elementos de uma lista de matriz
Você já aprendeu sobre loops nas seções anteriores. Bem, listas de arrays têm um forEach()
método próprio que recebe uma expressão lambda como parâmetro e pode executar uma ação em todos os elementos da lista de arrays.
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
ArrayList<Integer> oddNumbers = new ArrayList<>();
oddNumbers.add(1);
oddNumbers.add(3);
oddNumbers.add(5);
oddNumbers.add(7);
oddNumbers.add(9);
oddNumbers.forEach(number -> {
number = number * 2;
System.out.printf("%d ", number); // 2 6 10 14 18
});
System.out.println(oddNumbers.toString()); // [1, 3, 5, 7, 9]
}
}
Da última vez, a expressão lambda que você viu era uma única linha – mas pode ser maior. Aqui, o forEach()
método percorrerá a lista do array e passará cada elemento para a expressão lambda como o valor da number
variável.
A expressão lambda multiplicará o valor fornecido por 2 e o imprimirá no terminal. No entanto, a lista de arrays original permanecerá inalterada.
Como trabalhar com mapas de hash em Java
Mapas de hash em Java podem armazenar elementos em pares chave-valor. Esse tipo de coleção é comparável a dicionários em Python e objetos em JavaScript.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.printf(prices.toString()); // {orange=1.8, banana=1.0, apple=2.0, berry=2.5, guava=1.5}
}
}
Para criar mapas de hash, primeiro você terá que importar a java.util.HashMap
classe no topo do seu arquivo de origem.
Então você começa escrevendo HashMap
e, dentro de um par de sinais de menor que-maior, você escreverá o tipo de dado para a chave e o valor.
Aqui, as chaves serão strings e os valores serão doubles. Depois disso, o operador de atribuição, seguido por new HashMap<>()
.
Você pode usar o put()
método para inserir um registro no mapa hash. O método recebe a chave como primeiro parâmetro e seu valor correspondente como segundo parâmetro.
Há também o putIfAbsent()
método que adiciona o elemento fornecido somente se ele ainda não existir no mapa de hash.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.putIfAbsent("guava", 2.9);
System.out.println(prices.toString()); // {orange=1.8, banana=1.0, apple=2.0, berry=2.5, guava=1.5}
}
}
Você pode usar o get()
método para extrair um valor do mapa de hash. O método recebe a chave como parâmetro.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.get("banana")); // 1.000000
}
}
Existe outra variação deste método. O getOrDefault()
método funciona assim, get()
mas se a chave fornecida não for encontrada, ele retornará um valor padrão especificado.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.getOrDefault("jackfruit", 0.0)); // 0.0
}
}
O valor padrão deve corresponder ao tipo dos valores no mapa de hash. Você pode atualizar um valor em um mapa de hash usando o replace()
método:
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.replace("berry", 2.8);
System.out.printf(prices.toString()); // {orange=1.8, banana=1.0, apple=2.0, berry=2.8, guava=1.5}
}
}
Para remover elementos de um mapa hash, você pode usar o remove()
método apropriadamente chamado:
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.remove("guava");
System.out.printf(prices.toString()); // {orange=1.8, banana=1.0, apple=2.0, berry=2.5}
}
}
Se você precisar saber quantas entradas existem em um mapa hash, você pode fazer isso usando o size()
método:
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.size()); // 5
}
}
Por fim, se você quiser limpar um mapa de hash em Java, poderá fazer isso usando o clear()
método .
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.clear();
System.out.println(prices.toString()); // {}
}
}
Assim como nas listas de arrays, o método não aceita nenhum argumento nem retorna nenhum valor.
Como inserir ou substituir vários elementos em um mapa de hash
Se você quiser colocar vários elementos em um mapa hash de uma só vez, você pode fazer isso usando o putAll()
método:
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
HashMap<String, Double> morePrices = new HashMap<>();
prices.put("jackfruit", 2.9);
prices.put("pineapple", 1.1);
prices.put("tomato", 0.8);
prices.putAll(morePrices);
System.out.println(prices.toString()); // {orange=1.8, banana=1.0, apple=2.0, berry=2.5, pineapple=1.1, tomato=0.8, guava=1.5, jackfruit=2.9}
}
}
O método recebe outro mapa hash como parâmetro e adiciona seus elementos àquele para o qual o método foi chamado.
Você também pode usar o replaceAll()
método para atualizar vários valores em um mapa de hash.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
prices.replaceAll((fruit, price) -> price * 2);
System.out.println(prices.toString()); // {orange=3.6, banana=2.0, apple=4.0, berry=5.0, guava=3.0}
}
}
O método substituir tudo itera sobre o hashmap e passa cada par de valores-chave para a expressão lambda.
O primeiro parâmetro da expressão lambda é a chave e o segundo é o valor. Dentro da expressão lambda, você executa suas ações.
Como verificar se um mapa de hash contém um item ou se está vazio
Você pode usar os métodos containsKey()
e containsValue()
para verificar se um mapa de hash contém um valor ou não.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.containsKey("banana")); // true
System.out.println(prices.containsValue(2.5)); // true
}
}
A diferença entre os dois métodos é que o containsKey()
método verifica se a chave fornecida existe ou não e o containsValue()
método verifica se o valor fornecido existe ou não.
E se você quiser verificar se um mapa hash está vazio ou não, você pode fazer isso usando o isEmpty()
método:
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println(prices.isEmpty()); // false
}
}
Como o método retorna um valor booleano, você pode usá-lo em instruções if-else.
Como executar uma ação em todos os elementos de um mapa de hash
Assim como as listas de matrizes, os mapas de hash também têm seu próprio forEach()
método que você pode usar para executar um loop no mapa de hash e repetir uma determinada ação em cada entrada.
import java.util.HashMap;
public class Main {
public static void main (String[] args) {
HashMap<String, Double> prices = new HashMap<>();
prices.put("apple", 2.0);
prices.put("orange", 1.8);
prices.put("guava", 1.5);
prices.put("berry", 2.5);
prices.put("banana", 1.0);
System.out.println("prices after discounts");
prices.forEach((fruit, price) -> {
System.out.println(fruit + " - " + (price - 0.5));
});
}
}
// prices after discounts
// orange - 1.3
// banana - 0.5
// apple - 1.5
// berry - 2.0
// guava - 1.0
O método percorre cada entrada e passa a chave e o valor para a expressão lambda. Dentro do corpo da expressão lambda, você pode fazer o que quiser.
Classes e Objetos em Java
Aqui está uma definição útil de programação orientada a objetos :
POO (Programação Orientada a Objetos) é um paradigma de programação baseado no conceito de "objetos", que podem conter dados e código: dados na forma de campos (geralmente conhecidos como atributos ou propriedades) e código, na forma de procedimentos (geralmente conhecidos como métodos).
Imagine um sistema de gerenciamento de biblioteca onde os membros da biblioteca podem fazer login, dar uma olhada nos livros que já pegaram emprestado, solicitar novos e assim por diante.
Neste sistema, os usuários e os livros podem ser objetos. Esses objetos terão suas próprias propriedades, como nome e data de nascimento (no caso de um usuário) e título e autor no caso dos livros.
As classes em programação orientada a objetos são modelos para os objetos mencionados. Já discutimos as possíveis propriedades dos objetos usuário e livro.
Para criar uma nova User
classe, clique com o botão direito do mouse na src
pasta novamente. Em seguida, vá em Novo > Classe Java , nomeie-a User
e pressione Enter.
Mantendo as propriedades discutidas anteriormente em mente, seu código para a User
classe deve ser o seguinte:
import java.time.LocalDate;
public class User {
String name;
LocalDate birthDay;
}
Este LocalDate
é um tipo de dado de referência que representa uma data. Agora, volte ao Main.java
arquivo e crie uma nova instância desta classe:
import java.time.LocalDate;
public class Main {
public static void main (String[] args) {
User user = new User();
user.name = "Farhan";
user.birthDay = LocalDate.parse("1996-07-15");
System.out.printf("%s was born on %s.", user.name, user.birthDay.toString()); // Farhan was born on 15th July 1996.
}
}
Criar um novo usuário não é muito diferente de criar uma nova string ou array. Você começa escrevendo o nome da classe e, em seguida, o nome da instância ou do objeto.
Em seguida, você insere o operador de atribuição seguido pela new
palavra-chave e a chamada do construtor. O construtor é um método especial que inicializa o objeto.
O construtor inicializou as propriedades do objeto com valores padrões null
para todos esses tipos de referência.
Você pode acessar as propriedades do objeto escrevendo o nome do objeto seguido de um ponto e depois o nome da propriedade.
O LocalDate.parse()
método pode analisar uma data de uma string específica. Como birthDay
é um tipo de referência, você precisará usar o toString()
método para imprimir no console.
O que é um método?
As variáveis ou propriedades de uma classe descrevem o estado de seus objetos. Os métodos, por outro lado, descrevem o comportamento.
Por exemplo, você pode ter um método dentro de sua User
classe que calcule a idade do usuário.
import java.time.Period;
import java.time.LocalDate;
public class User {
String name;
LocalDate birthDay;
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
}
Aqui, a this
palavra-chave representa a instância atual da classe. Comece escrevendo o tipo de retorno do método. Como a idade de um usuário é um inteiro, o tipo de retorno deste método será int
.
Após o tipo de retorno, escreva o nome do método, seguido por um par de parênteses.
Em seguida, escreva o corpo do método entre chaves. A Period
classe em Java expressa um período de tempo no sistema de calendário ISO-8601. O LocalDate.now()
método retorna a data atual.
Portanto, a Period.between(this.birthDay, LocalDate.now()).getYears()
chamada do método retornará a diferença entre a data atual e a data de nascimento em anos.
Agora, de volta ao Main.java
arquivo, você pode chamar este método da seguinte maneira:
import java.time.LocalDate;
public class Main {
public static void main (String[] args) {
User user = new User();
user.name = "Farhan";
user.birthDay = LocalDate.parse( "1996-07-15");
System.out.printf("%s is %s years old.", user.name, user.age()); // Farhan a 26 years old.
}
}
Os métodos também podem aceitar parâmetros. Por exemplo, se você quiser criar um método borrow()
para inserir novos livros na lista de livros emprestados deste usuário, faça o seguinte:
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
public class User {
String name;
LocalDate birthDay;
ArrayList<String> borrowedBooks = new ArrayList<String>();
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(String bookTitle) {
this.borrowedBooks.add(bookTitle);
}
}
De volta ao Main.java
arquivo, você pode chamar esse método da seguinte maneira:
public class Main {
public static void main (String[] args) {
User user = new User();
user.name = "Farhan";
user.borrow("Carmilla");
user.borrow("Hard West");
System.out.printf("%s has borrowed these books: %s", user.name, user.borrowedBooks.toString()); // Farhan has borrowed these books: [Carmilla, Hard West]
}
}
Vamos criar uma classe para os livros também:
import java.util.ArrayList;
public class Book {
String title;
ArrayList<String> authors = new ArrayList<String>();
}
Os livros geralmente têm vários autores. Agora você pode criar uma nova instância do livro no Main.java
arquivo.
import java.time.LocalDate;
public class Main {
public static void main (String[] args) {
User user = new User();
user.name = "Farhan";
user.birthDay = LocalDate.parse( "1996-07-15");
Book book = new Book();
book.title = "Carmilla";
book.authors.add("Sheridan Le Fanu");
System.out.printf("%s is written by %s", book.title, book.authors.toString()); // Carmilla is written by [Sheridan Le Fanu]
}
}
Agora vamos voltar ao User.java
arquivo e criar um relacionamento entre os usuários e os livros:
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
public class User {
String name;
LocalDate birthDay;
ArrayList<Book> borrowedBooks = new ArrayList<Book>();
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
this.borrowedBooks.add(book);
}
}
Em vez de usar uma lista de array de strings, agora você está usando uma lista de array de livros para armazenar os livros emprestados por este usuário.
Como o tipo de argumento do método mudou, você terá que atualizar o código no Main.java
arquivo adequadamente:
import java.time.LocalDate;
public class Main {
public static void main (String[] args) {
User user = new User();
user.name = "Farhan";
user.birthDay = LocalDate.parse( "1996-07-15");
Book book = new Book();
book.title = "Carmilla";
book.authors.add("Sheridan Le Fanu");
user.borrow(book);
System.out.printf("%s has borrowed these books: %s", user.name, user.borrowedBooks.toString()); // Farhan has borrowed these books: [Book@30dae81]
}
}
Tudo funciona bem, exceto pelo fato de que as informações do livro não foram impressas corretamente.
Espero que você se lembre do toString()
método. Quando você chama user.borrowedBooks.toString()
o compilador, ele percebe que os itens armazenados no arraylist são objetos ou tipos de referência. Então, ele começa a chamar os toString()
métodos dentro desses itens.
O problema é que não há uma implementação adequada de toString()
na sua Book
classe. Abra Book.java
e atualize o código da seguinte maneira:
import java.util.ArrayList;
public class Book {
String title;
ArrayList<String> authors = new ArrayList<String>();
public String toString() {
return String.format("%s by %s", this.title, this.authors.toString());
}
}
O toString()
método agora retorna uma string bem formatada em vez da referência ao objeto. Execute o código novamente e, desta vez, a saída deverá ser Farhan has borrowed these books: [Carmilla by [Sheridan Le Fanu]]
.
Como você pode ver, poder projetar seu software em torno de entidades da vida real o torna muito mais relacionável. Embora haja apenas uma lista de arrays e um monte de strings em jogo, parece que uma operação real de empréstimo de livros está acontecendo.
O que é sobrecarga de método?
Em Java, vários métodos podem ter o mesmo nome se seus parâmetros forem diferentes. Isso se chama sobrecarga de método.
Um exemplo pode ser o borrow()
método da User
classe. No momento, ele aceita um único livro como parâmetro. Vamos criar uma versão sobrecarregada que possa aceitar um array de livros.
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
import java.util.Arrays;
public class User {
private String name;
private LocalDate birthDay;
private ArrayList<Book> borrowedBooks = new ArrayList<Book>();
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getBorrowedBooks() {
return this.borrowedBooks.toString();
}
User (String name, String birthDay) {
this.name = name;
this.birthDay = LocalDate.parse(birthDay);
}
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
borrowedBooks.add(book);
}
void borrow(Book[] books) {
borrowedBooks.addAll(Arrays.asList(books));
}
}
O tipo de retorno e o nome do novo método são idênticos aos anteriores, mas este aceita um array de Book
objetos em vez de um único objeto.
Vamos atualizar o Main.java
arquivo para usar esse método sobrecarregado.
public class Main {
public static void main (String[] args) {
User user = new User("Farhan", "1996-07-15");
Book book1 = new Book("Carmilla", new String[]{"Sheridan Le Fanu"});
Book book2 = new Book("Frankenstein", new String[]{"Mary Shelley"});
Book book3 = new Book("Dracula", new String[]{"Bram Stoker"});
user.borrow(new Book[]{book1, book2});
user.borrow(book3);
System.out.printf("%s has borrowed these books: %s", user.getName(), user.getBorrowedBooks());
}
}
Como você pode ver, o borrow()
método agora aceita um array de livros ou um único objeto de livro sem nenhum problema.
O que são construtores em Java?
Construtores são um tipo especial de método que existe em todas as classes e, sempre que você cria um novo objeto de uma classe, o compilador o chama.
Como o método é chamado durante a construção de um objeto, ele é chamado de construtor. Por padrão, um construtor atribui valores padrão a todas as suas propriedades.
Para substituir o construtor padrão, você precisa criar um novo método em suas classes com o mesmo nome da classe.
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
public class User {
public String name;
public LocalDate birthDay;
public ArrayList<Book> borrowedBooks = new ArrayList<Book>();
User (String name, String birthDay) {
this.name = name;
this.birthDay = LocalDate.parse(birthDay);
}
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
this.borrowedBooks.add(book);
}
}
Agora que você tem um construtor, em vez de analisar a data de uma string no Main.java
arquivo, você pode fazer isso aqui.
Isso ocorre porque o formato do aniversário é uma preocupação da User
turma e a Main
turma não precisa se preocupar com isso.
O mesmo tratamento para a classe de livros também:
import java.util.ArrayList;
import java.util.Arrays;
public class Book {
public String title;
public ArrayList<String> authors = new ArrayList<String>();
Book(String title, String[] authors) {
this.title = title;
this.authors = new ArrayList<String>(Arrays.asList(authors));
}
public String toString() {
return String.format("%s by %s", this.title, this.authors.toString());
}
}
Novamente, o tipo de authors
coleção não é uma preocupação do Main
classe. A maneira mais básica de trabalhar com um conjunto de valores em Java é com um array.
Então você receberá os nomes dos autores como uma matriz da Main
classe e criará uma lista de matrizes a partir deles na Book
classe.
Agora você terá que passar esses parâmetros para o construtor ao criar um novo usuário ou objeto de livro no Main.java
arquivo.
import java.util.ArrayList;
public class Main {
public static void main (String[] args) {
User user = new User("Farhan", "1996-07-15");
Book book = new Book("Carmilla", new String[]{"Sheridan Le Fanu"});
user.borrow(book);
System.out.printf("%s has borrowed these books: %s", user.name, user.borrowedBooks.toString()); // Farhan has borrowed these books: [Carmilla, Hard West]
}
}
Veja como já está mais limpo. Mas logo ficará melhor.
O que são modificadores de acesso em Java?
Você já viu a palavra-chave public
várias vezes. Este é um dos modificadores de acesso em Java.
Existem quatro modificadores de acesso em Java:
Tipo primitivo | Classe Wrapper |
Padrão | Acessível dentro do pacote |
Público | Acessível em qualquer lugar |
Privado | Acessível dentro da classe |
Protegido | Acessível dentro da classe e subclasses |
Por enquanto, discutirei os Default
modificadores de acesso Public
e . serão discutidos em uma seção posterior.Private
Protected
Você já aprendeu sobre classes. Pacotes são coleções de várias classes separadas por sua funcionalidade.
Por exemplo, se você estiver criando um jogo, você pode colocar todas as classes relacionadas à física em um pacote separado e as relacionadas aos gráficos em outro.
Os pacotes estão fora do escopo deste livro, mas à medida que você continuar trabalhando em projetos cada vez maiores, você pegará o jeito deles.
O Public
modificador de acesso é bastante autoexplicativo. Essas variáveis, métodos ou classes podem ser acessados de qualquer outra classe ou pacote do seu projeto.
Aqueles Private
, por outro lado, são o oposto. Estão disponíveis apenas dentro da sua classe.
Veja a User
classe, por exemplo. O nome e a data de nascimento de um usuário não devem ser acessíveis externamente.
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
public class User {
private String name;
private LocalDate birthDay;
private ArrayList<Book> borrowedBooks = new ArrayList<Book>();
User (String name, String birthDay) {
this.name = name;
this.birthDay = LocalDate.parse(birthDay);
}
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
borrowedBooks.add(book);
}
}
Melhor assim. Atualize a Book
classe também para ocultar o título e as informações do autor do mundo exterior.
import java.util.ArrayList;
import java.util.Arrays;
public class Book {
private String title;
private ArrayList<String> authors = new ArrayList<String>();
Book(String title, String[] authors) {
this.title = title;
this.authors = new ArrayList<String>(Arrays.asList(authors));
}
public String toString() {
return String.format("%s by %s", this.title, this.authors.toString());
}
}
Como as propriedades se tornaram privadas agora, a System.out.println()
linha no Main.java
arquivo não conseguirá acessá-las diretamente, o que causará um problema.
A solução para este programa é escrever métodos públicos que outras classes podem usar para acessar essas propriedades.
O que são os métodos Getter e Setter em Java?
Getters e setters são métodos públicos em classes usados para ler e escrever propriedades privadas.
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
public class User {
private String name;
private LocalDate birthDay;
private ArrayList<Book> borrowedBooks = new ArrayList<Book>();
public String getName() {
return this.name;
}
public String getBirthDay() {
return this.birthDay.toString();
}
public String getBorrowedBooks() {
return this.borrowedBooks.toString();
}
User (String name, String birthDay) {
this.name = name;
this.birthDay = LocalDate.parse(birthDay);
}
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
borrowedBooks.add(book);
}
}
As getName()
variáveis e getBorrowedBooks()
são responsáveis por retornar o valor das variáveis name
e .borrowedBooks
Na verdade, você nunca acessa a variável de aniversário a partir do age()
método, então um getter não é necessário.
Como o tipo da borrowedBooks
variável não é uma preocupação da Main
classe, o getter garante que o valor seja retornado no formato adequado.
Agora atualize o código no Main.java
arquivo para usar estes métodos:
public class Main {
public static void main (String[] args) {
User user = new User("Farhan", "1996-07-15");
Book book = new Book("Carmilla", new String[]{"Sheridan Le Fanu"});
user.borrow(book);
System.out.printf("%s has borrowed these books: %s", user.getName(), user.getBorrowedBooks());
}
}
Excelente. Ficou ainda mais limpo e fácil de ler. Assim como os getters, existem setters para escrever valores nas propriedades privadas.
Por exemplo, você pode querer permitir que o usuário altere seu nome ou data de nascimento. O borrow()
método já funciona como um setter para a borrowedBooks
lista de arrays.
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
public class User {
private String name;
private LocalDate birthDay;
private ArrayList<Book> borrowedBooks = new ArrayList<Book>();
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void setBirthDay(String birthDay) {
this.birthDay = LocalDate.parse(birthDay);
}
public String getBorrowedBooks() {
return this.borrowedBooks.toString();
}
User (String name, String birthDay) {
this.name = name;
this.birthDay = LocalDate.parse(birthDay);
}
int age() {
return Period.between(this.birthDay, LocalDate.now()).getYears();
}
void borrow(Book book) {
borrowedBooks.add(book);
}
}
Agora você pode chamar o setName()
método com o nome que quiser atribuir ao usuário. Da mesma forma, o setBirthDay()
método pode definir a data de aniversário.
Você Book
também pode implementar alguns getters e setters para a classe.
import java.util.ArrayList;
import java.util.Arrays;
public class Book {
private String title;
private ArrayList<String> authors = new ArrayList<String>();
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthors() {
return this.authors.toString();
}
public void setTitle(String[] authors) {
this.authors = new ArrayList<String>(Arrays.asList(authors));
}
Book(String title, String[] authors) {
this.title = title;
this.authors = new ArrayList<String>(Arrays.asList(authors));
}
public String toString() {
return String.format("%s by %s", this.title, this.authors.toString());
}
}
Agora você não pode acessar essas propriedades diretamente. Em vez disso, você terá que usar um dos getters ou setters.
O que é herança em Java?
Herança é outro grande recurso da programação orientada a objetos. Imagine que você tem três tipos de livros: os tradicionais, os e-books e os audiolivros.
Embora tenham semelhanças, como título e autor, também apresentam algumas diferenças. Por exemplo, os livros tradicionais e os e-books têm contagem de páginas, enquanto os audiolivros têm duração. Os e-books também têm formatos como PDF ou EPUB.
Portanto, usar a mesma classe para todos os três não é uma opção. Isso não significa que você precisará criar três classes separadas com pequenas diferenças. Você pode simplesmente criar classes separadas para e-books e audiolivros e fazer com que herdem as propriedades e métodos da Book
classe.
Vamos começar adicionando a contagem de páginas na Book
classe:
import java.util.ArrayList;
import java.util.Arrays;
public class Book {
private String title;
private int pageCount;
private ArrayList<String> authors = new ArrayList<String>();
Book(String title, int pageCount, String[] authors) {
this.title = title;
this.pageCount = pageCount;
this.authors = new ArrayList<String>(Arrays.asList(authors));
}
public String length() {
return String.format("%s is %d pages long.", this.title, this.pageCount);
}
public String toString() {
return String.format("%s by %s", this.title, this.authors.toString());
}
}
Como você não vai usar getters e setters nestes exemplos, uma limpeza pareceu uma boa ideia. O length()
método retorna o comprimento do livro como uma string.
Agora crie uma nova classe Java chamada AudioBook
e coloque o seguinte código nela:
public class AudioBook extends Book{
private int runTime;
AudioBook(String title, String[] authors, int runTime) {
super(title, 0, authors);
this.runTime = runTime;
}
}
A extends
palavra-chave informa ao compilador que esta classe é uma subclasse da Book
classe pai. Isso significa que esta classe herda todas as propriedades e métodos da classe pai.
Dentro do AudioBook
método construtor, você define o tempo de execução do audiolivro, o que é bom, mas você também terá que chamar manualmente o construtor da classe pai.
A super
palavra-chave em Java se refere à classe pai, então super(title, 0, authors)
essencialmente chama o método construtor pai com os parâmetros necessários.
Como os audiolivros não têm páginas, definir a contagem de páginas como zero pode ser uma solução fácil.
Ou você pode criar uma versão sobrecarregada do Book
método construtor que não requer a contagem de páginas.
Em seguida, crie outra classe Java nomeada Ebook
com o seguinte código:
public class Ebook extends Book{
private String format;
Ebook(String title, int pageCount, String[] authors, String format) {
super(title, pageCount, authors);
this.format = format;
}
}
Esta classe é em grande parte idêntica à Book
classe, exceto pelo fato de ter uma propriedade de formato.
public class Main {
public static void main (String[] args) {
Book book = new Book("Carmilla", 200, new String[]{"Sheridan Le Fanu"});
Ebook ebook = new Ebook("Frankenstein", 220, new String[]{"Mary Shelley"}, "EPUB");
AudioBook audioBook = new AudioBook("Dracula", new String[]{"Bram Stoker"}, 160);
System.out.println(book.toString()); // Carmilla by [Sheridan Le Fanu]
System.out.println(ebook.toString()); // Frankenstein by [Mary Shelley]
System.out.println(audioBook.toString()); // Dracula by [Bram Stoker]
}
}
Até agora, tudo está funcionando bem. Mas você se lembra do length()
método que escreveu na Book
aula? Ele funciona para os livros comuns, mas não funciona nos e-books.
Isso ocorre porque a propriedade de contagem de páginas está marcada como private
e nenhuma outra classe, exceto que Book
ela poderá acessá-la. O título também é uma private
propriedade.
Abra o Book.java
arquivo e marque as propriedades title
e pageCount
como protegidos.
import java.util.ArrayList;
import java.util.Arrays;
public class Book {
protected String title;
protected int pageCount;
private ArrayList<String> authors = new ArrayList<String>();
Book(String title, int pageCount, String[] authors) {
this.title = title;
this.pageCount = pageCount;
this.authors = new ArrayList<String>(Arrays.asList(authors));
}
public String length() {
return String.format("%s is %d pages long.", this.title, this.pageCount);
}
public String toString() {
return String.format("%s by %s", this.title, this.authors.toString());
}
}
Isso os tornará acessíveis a partir das subclasses. Os audiolivros têm outro problema com o length()
método.
Os audiolivros não possuem contagem de páginas. Eles têm duração, e essa diferença invalidará o método de duração.
Uma maneira de resolver esse problema é substituir o length()
método.
Como substituir um método em Java
Como o nome sugere, substituir significa cancelar o efeito de um método substituindo-o por outra coisa.
public class AudioBook extends Book{
private int runTime;
AudioBook(String title, String[] authors, int runTime) {
super(title, 0, authors);
this.runTime = runTime;
}
@Override
public String length() {
return String.format("%s is %d minutes long.", this.title, this.runTime);
}
}
Você sobrescreve um método da classe pai reescrevendo-o na subclasse. A @Override
palavra-chave é uma anotação. Anotações em Java são metadadas.
Não é obrigatório anotar o método dessa forma. Mas, se você fizer isso, o compilador saberá que o método anotado substituirá um método pai e garantirá que você esteja seguindo todas as regras de substituição.
Por exemplo, se você cometer um erro no nome do método e ele não corresponder a nenhum método do pai, o compilador informará que o método não está atualizando nada.
public class Main {
public static void main (String[] args) {
AudioBook audioBook = new AudioBook("Dracula", new String[]{"Bram Stoker"}, 160);
System.out.println(audioBook.length()); // Dracula is 160 minutes long.
}
}
Legal, não é? Ao sobrescrever um método em Java, lembre-se de que tanto o método original quanto o sobrescrito devem ter o mesmo tipo de retorno, o mesmo nome e os mesmos parâmetros.
Conclusão
Gostaria de agradecer ao fundo do meu coração pelo tempo que você dedicou à leitura deste livro. Espero que tenha aproveitado e aprendido todos os conceitos fundamentais de Java.
No código aberto, tenho certeza de que, para realmente fazer algo bem, é preciso envolver muitas pessoas. -
Até a próxima, procure seguros e continue aprendend