100% acharam este documento útil (1 voto)
315 visualizações41 páginas

Sintaxe Da Linguagem Java

O documento descreve conceitos básicos de programação em Java, incluindo declaração de variáveis, tipos de dados primitivos, operadores, estruturas condicionais, loops, arrays, métodos e classes. Ele fornece exemplos de como esses elementos são usados na linguagem Java.

Enviado por

BL Pipas
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
100% acharam este documento útil (1 voto)
315 visualizações41 páginas

Sintaxe Da Linguagem Java

O documento descreve conceitos básicos de programação em Java, incluindo declaração de variáveis, tipos de dados primitivos, operadores, estruturas condicionais, loops, arrays, métodos e classes. Ele fornece exemplos de como esses elementos são usados na linguagem Java.

Enviado por

BL Pipas
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Variáveis

Variáveis são usadas para armazenar dados na memória durante a execução do


programa.

Declarando variáveis

Usando variáveis

Tipos inteiros

Também podem ser atribuídos usando a notação octal ou hexadecimal.

Os dígitos em um número podem ser separados por um sublinhado apenas para


melhorar a legibilidade:

Tipos de ponto flutuante

Você pode anexar um caractere F ao fim da variável para indicar um float:

1
Char
O char contém um único caractere Unicode, delimitado por aspas simples:

Notação hexadecimal especial que dá acesso a todos os caracteres Unicode:

Tipo booleano
O tipo booleano pode armazenar um valor booleano, que é um valor que só pode
ser verdadeiro ou falso. Esses valores são especificados com as palavras-chave
true ou false:

Operadores aritméticos
Existem quatro operadores aritméticos básicos, bem como o operador de módulo
(%), que é usado para obter o restante da divisão:

Operadores de atribuição combinados

Operadores de incremento e decremento

Ambos podem ser usados antes ou depois de uma variável:

Operadores de comparação
Os operadores de comparação comparam dois valores e retornam verdadeiro ou
falso.

2
Operadores lógicos

Operador precedente

String
A classe String em Java é um tipo de dados que pode conter literais de string.
String é um tipo de dados de referência, assim como todos os tipos de dados não
e vem sempre entre aspas duplas.

Concatenação de Strings
O sinal de + é usado para concatenar(unir) duas strings.

Caracteres de escape

3
Comparação de Strings
A maneira de comparar duas strings é usar o método equals da classe String. Se
o operador de igualdade (==) for usado, os endereços de memória serão
comparados:

Classe StringBuffer
As strings em Java são imutáveis. Depois que um objeto String é criado, o
conteúdo não pode ser alterado, a menos que toda a string seja completamente
substituída.

Arrays

Declaração de array
int [] x;

Alocação de matriz
A matriz é alocada com a palavra-chave new, seguida novamente pelo tipo de
dados e um conjunto de colchetes contendo o comprimento da matriz - o número
fixo de elementos que a matriz pode conter.

Atribuição de matriz
Referenciando os valores aos elementos
y [0] = 1;
y [1] = 2;
y [2] = 3;
Ou declarar de forma mais compacta:

4
Para acessar os elementos:
System.out.print (x [0] + x [1] + x [2]); // "6"

Matrizes multidimensionais
Os arrays multidimensionais têm colchetes adicionais. Eles podem ter qualquer
número de dimensões e, para cada dimensão, outro conjunto de colchetes é
adicionado:

Classe ArrayList
Algo importante a se ter em mente sobre os arrays é que seu comprimento é fixo
e não há como alterar seu tamanho.

Para os casos em que uma matriz redimensionável é necessária, a classe


ArrayList pode ser usada, que está localizada no pacote java.util. Os itens na
ArrayList são armazenados como o tipo de objeto genérico. O ArrayList pode,
portanto, conter qualquer tipo de dados, exceto para primitivos (usar
String,Double,Float,Integer,Boolean ):

Métodos da classe ArrayList :

Condicionais

Declaração If
A instrução if só será executada se a condição entre parênteses for avaliada
como verdadeira. A condição pode incluir qualquer um dos operadores lógicos e
de comparação:

5
Para testar outras condições

cláusula else no final, que será executada se todas as condições anteriores


forem falsas:

Switch
A instrução switch verifica a igualdade entre um inteiro e uma série de rótulos
case. Em seguida, ele executa o caso correspondente. A instrução pode conter
qualquer número de casos e pode terminar com um rótulo default para lidar com
todos os outros casos:

Pode-se usar uma String nos cases também.

Operador ternário
O operador usa três expressões. Se a primeira for avaliada como verdadeira, a
segunda expressão será retornada, mas se for falsa, a terceira será avaliada e
retornada:

Loops
While
O loop while percorre o bloco de código apenas se a condição especificada for
verdadeira e continuará o loop enquanto a condição permanecer verdadeira.

Do while
O loop do while funciona da mesma maneira que o loop while, exceto que verifica
a condição após o bloco de código. Portanto, ele sempre será executado no bloco
de código pelo menos uma vez:
6
For
O loop for é usado para passar por um bloco de código um número específico de
vezes. Ele usa três parâmetros. O primeiro parâmetro inicializa um contador e é
sempre executado uma vez, antes do loop. O segundo parâmetro contém a condição
para o loop e é verificado antes de cada iteração. O terceiro parâmetro contém
o incremento do contador e é executado ao final de cada iteração:

For-each
O loop “for each” fornece uma maneira fácil de iterar por meio de arrays.
Dentro do for declara-se um “apelido qualquer” do mesmo tipo do array .

Break e continue
A palavra-chave break termina a estrutura de loop e continue ignora o resto da
iteração atual e continua no início da próxima iteração:
Para sair de um loop acima do atual, esse loop deve primeiro ser rotulado
adicionando-se um nome seguido de dois pontos antes dele. Com esse rótulo no
lugar, ele agora pode ser usado como um argumento para a instrução break,
informando de qual loop sair. Isso também funciona com a palavra-chave continue
para pular para a próxima iteração do loop nomeado.

Métodos
Métodos são blocos de código reutilizáveis que só são executados
quando chamados.

Métodos de definição
Você pode criar um método digitando void seguido pelo nome do método, um
conjunto de parênteses e um bloco de código. A palavra-chave void significa que
o método não retornará um valor. A convenção de nomenclatura para métodos é a

7
mesma que para variáveis - um nome descritivo com a primeira palavra em
minúsculas e a primeira letra de qualquer palavra subsequente em maiúscula:

Chamando método
O método anterior simplesmente imprimirá uma mensagem de texto. Para invocá-lo
(chamá-lo) do método principal, uma instância da classe MyApp deve ser criada
primeiro. O operador ponto ( . ) é então usado após o nome da instância para
acessar seus membros, que incluem o método myPrint:

Parâmetros do método
Os parênteses que seguem o nome do método são usados para passar argumentos
para o método. Para fazer isso, os parâmetros correspondentes devem primeiro
ser adicionados à declaração do método na forma de uma lista separada por
vírgulas:

Um método pode ser definido para receber qualquer número de argumentos e eles
podem ter quaisquer tipos de dados. Apenas certifique-se de que o método seja
chamado com os mesmos tipos e número de argumentos:

Método com retorno


Um método pode retornar um valor. A palavra-chave void é então substituída pelo
tipo de dados que o método retornará, e a palavra-chave return é adicionada ao
corpo do método com um argumento do tipo de retorno especificado:

8
Return
instrução de salto que faz com que o método saia e retorne o valor especificado
para o local onde o método foi chamado. Por exemplo, o método anterior pode ser
passado como um argumento para o método getString porque o método é avaliado
como uma string:

Sobrecarga de método
É possível declarar vários métodos com o mesmo nome, desde que os parâmetros
variem em tipo ou número . É um recurso poderoso que permite a um método lidar
com uma variedade deargumentos sem que o programador precise estar ciente do
uso de métodos diferentes:

Passando argumentos
Em Java, todos os parâmetros do método são passados por valor. Na verdade, eles
não podem ser passados por referência. Para tipos de dados de valor (tipos
primitivos), isso significa que apenas uma cópia local da variável é alterada
dentro do método, portanto, a alteração não afetará a variável original. Para
tipos de dados de referência (classes, interfaces e arrays), isso significa que
apenas uma cópia do endereço de memória é passada para o método. Portanto, se
todo o objeto é substituído, a alteração não se propagará de volta para o
chamador, mas as alterações no objeto afetarão o original, pois a cópia aponta
para o mesmo local da memória:

9
Classes
Uma classe é um modelo usado para criar objetos. As classes são compostas por
membros, sendo os dois principais campos e métodos. Os campos são variáveis que
mantêm o estado do objeto, enquanto os métodos definem o que o objeto pode
fazer - os chamados comportamentos do objeto:

Criação de objeto
Para acessar um campo ou método de classe não estático de fora da classe de
definição, um objeto da classe deve primeiro ser criado. Isso é feito usando a
palavra-chave new, que criará um novo objeto na memória do sistema:

Um objeto também é chamado de instância . O objeto conterá seu próprio conjunto


de campos, que pode conter valores diferentes daqueles de outras instâncias da
classe.

Acessando membros do objeto


Além de criar o objeto, os membros da classe que devem ser acessíveis além de
seu pacote precisam ser declarados como públicos na definição da classe:

Os membros deste objeto agora podem ser usados através o operador ponto( . )
após o nome da instância:

Construtor
Uma classe pode ter um construtor , um tipo especial de método usado para
instanciar (construir) o objeto. Ela sempre tem o mesmo nome da classe e não
tem um tipo de retorno, pois retorna implicitamente uma nova instância da
classe. Para ser acessível a partir de outra classe que não esteja em seu
10
pacote, ele precisa ser declarado com o modificador de acesso public Quando uma
nova instância da classe MyRectangle é criada usando a nova sintaxe, o método
construtor é chamado, que no exemplo a seguir define os campos com os valores
padrão especificados:

O construtor pode ter uma lista de parâmetros, como qualquer outro método.
Conforme mostrado no código a seguir, isso pode ser usado para fazer com que os
valores iniciais dos campos dependam dos parâmetros passados quando o objeto é
criado:

Palavra this
Dentro do construtor, assim como em outros métodos pertencentes ao objeto, uma
palavra-chave especial chamada this pode ser usada. Esta palavra-chave é uma
referência para a instância atual da classe. Se, por exemplo, os parâmetros do
construtor têm os mesmos nomes que os campos correspondentes, então os campos
ainda podem ser acessados usando a palavra-chave this.

Sobrecarga do construtor
Para oferecer suporte a listas de parâmetros diferentes, o construtor pode ser
sobrecarregado. No exemplo a seguir, se a classe for instanciada sem nenhum
parâmetro, os campos serão atribuídos aos valores padrão especificados. Com um
parâmetro, ambos os campos serão definidos com o valor fornecido e, com dois
parâmetros, cada campo receberá um valor separado. A tentativa de criar um
objeto com o número errado de argumentos ou com tipos de dados incorretos

11
resultará em um erro em tempo de compilação, assim como com qualquer outro
método:

Encadeamento de construtor
Você também pode usar a palavra-chave this para chamar um construtor de outro.
Conhecido como encadeamento de construtor , permite maior reutilização de
código. Observe que a palavra-chave aparece como uma chamada de método e deve
estar na primeira linha do construtor:

Valores de campo iniciais


Se houver campos na classe que precisam ser atribuídos a valores padrão, como
no primeiro construtor mostrado, os campos podem simplesmente ser atribuídos ao
mesmo tempo em que são declarados. Esses valores iniciais serão atribuídos
antes que o construtor seja chamado:

Construtor padrão
É possível criar uma classe mesmo que nenhum construtor seja definido. Isso
ocorre porque o compilador criará automaticamente um construtor sem parâmetros
padrão:

Null
A constante null é utilizada para representar um objeto não inicializada. Ele
só pode ser atribuído a objetos e não a variáveis de tipos primitivos. O
operador igual (==) pode ser usado para testar se um objeto é nulo:

12
Valores padrão
O valor padrão de um objeto é null. Para tipos de dados primitivos, os valores
padrão são os seguintes:
Tipos numéricos = 0,
char tem o caractere Unicode para zero (\0000)
booleano é falso.

Estatic
A palavra-chave static é usada para criar campos e métodos que podem ser
acessados sem a necessidade de criar uma instância da classe. Membros estáticos
(classe) existem apenas em uma cópia, que pertence à própria classe, enquanto
membros de instância (não estáticos) são criados como novas cópias para cada
novo objeto. Isso significa que os métodos estáticos não podem usar membros de
instância porque esses métodos não fazem parte de uma instância. Por outro
lado, os métodos de instância podem usar membros estáticos e de instância:

Acessando membros estáticos


Para acessar um membro estático de fora da classe, o nome da classe é usado
seguido pelo operador ponto. Esse operador é o mesmo usado para acessar os
membros da instância, mas para alcançá-los é necessária uma referência de
objeto. Tentar acessar um membro estático usando uma referência de objeto (em
vez do nome da classe) resultará em um aviso, pois torna mais difícil ver que
um membro estático está sendo usado:

13
Métodos estáticos
A vantagem dos membros estáticos é que eles podem ser usados por outras classes
sem a necessidade de criar uma instância da classe. Os campos devem, portanto,
ser declarados estáticos quando apenas uma única instância da variável é
necessária. Os métodos devem ser declarados estáticos se executarem uma função
genérica independente de quaisquer variáveis de instância. Um bom exemplo disso
é a classe Math, que contém apenas métodos e campos estáticos:

Campos estáticos
Os campos estáticos têm a vantagem de persistir durante toda a vida útil do
aplicativo. Isso significa que eles podem ser usados, por exemplo, para
registrar o número de vezes que um método foi chamado em todas as instâncias da
classe. O valor inicial para um campo estático será definido apenas uma vez,
algum tempo antes da classe ou campo ser usado:

Blocos de inicialização estáticos


Um bloco de inicialização estático pode ser usado se a inicialização de campos
estáticos exigir mais de uma linha ou alguma outra lógica. Este bloco, ao
contrário do construtor, será executado apenas uma vez, ao mesmo tempo em que
os campos estáticos são inicializados:

Blocos de inicialização de instância


Um bloco de inicialização fornece um método alternativo para atribuir campos de
instância. Este bloco é colocado no nível da classe, assim como o bloco de
inicialização estático, mas sem o uso da palavra-chave static. Qualquer código
colocado entre os colchetes será copiado para o início de cada construtor pelo
compilador:

14
Herança
A herança permite que uma classe adquira os membros de outra classe. No exemplo
a seguir, Apple herda de Fruit. Isso é especificado com a palavra-chave
extends. A fruta então se torna a superclasse da Maçã, que por sua vez se torna
uma subclasse de Frutas. Além de seus próprios membros, a Apple ganha todos os
membros acessíveis no Fruit, exceto para seus construtores:

Object
Uma classe em Java pode herdar apenas de uma superclasse e, se nenhuma classe
for especificada, ela herdará implicitamente de Object. Portanto, Object é a
classe raiz de todas as classes:

Upcasting
Conceitualmente, uma subclasse é uma especialização da superclasse. Isso
significa que a Maçã é um tipo de Fruta, bem como um Objeto, e pode, portanto,
ser usada em qualquer lugar onde uma Fruta ou Objeto seja esperado. Por
exemplo, se uma instância da Apple for criada, ela pode ser upcast para Fruit
porque a subclasse contém tudo na superclasse:

A maçã é então vista como uma fruta, então apenas os membros da fruta podem ser
acessados:

15
Downcasting
Quando a classe é reduzida de volta para um Apple, os campos que são
específicos para o Apple terão sido preservados. Isso porque a fruta continha
apenas a maçã - ela não a converteu. O downcast deve ser feito explicitamente
usando o formato Java Cast porque o downcast de um objeto Fruit real em um
Apple não é permitido:

Operador de instância
Como precaução de segurança, você pode testar para ver se um objeto pode ser
lançado em uma classe específica usando o operador instanceof. Este operador
retorna verdadeiro se o objeto do lado esquerdo puder ser convertido no tipo do
lado direito sem causar uma exceção:

Overriding
Um membro em uma subclasse pode redefinir um membro em sua superclasse. Isso
geralmente é feito para dar novas implementações aos métodos de instância.

Substituindo membros
No exemplo a seguir, o método getArea de Rectangle é substituído no Triangle,
redeclarando-o com a mesma assinatura de método. A assinatura inclui o nome,
parâmetros e tipo de retorno do método. No entanto, o nível de acesso pode ser
alterado para permitir mais acesso do que o método que está sendo substituído:

Override annotation
Para mostrar que essa substituição foi intencional, a anotação @Override deve
ser colocada antes do método. Esta anotação foi adicionada no Java 5 para
evitar modificações acidentais:

16
Invocar o método getArea de uma instância de Triangle chamará a versão de
Triangle do método:

Se a instância de Triangle for convertida em Rectangle, a versão de Triangle do


método ainda será chamada porque a versão de Rectangle foi substituída:

Hiding members
Se um método de classe chamado newArea for adicionado a Rectangle e redefinido
em Triangle, a versão de Triangle do método ocultará apenas a implementação de
Rectangle. Por causa disso, a anotação @Override não é usada:

Prevenção de herança de método


Para evitar que um método de instância seja sobrescrito em subclasses, você
pode declará-lo com o modificador final:

Lembre-se de que a ordem dos modificadores do método não é opcional. O


compilador indicará quando os modificadores aparecerem na ordem errada.

Acessando métodos subscrito


Um método sobrescrito ainda pode ser acessado de dentro dos métodos de
instância da subclasse usando a palavra-chave super. Esta palavra-chave é uma
referência à instância atual da superclasse

17
Chamando construtor pai
Outro lugar onde a palavra-chave super pode ser usada é na primeira linha de um
construtor. Lá, ele pode realizar uma chamada de método que invoca o construtor
da superclasse:

Se a primeira linha de um construtor não for uma chamada para outro construtor,
o compilador Java adicionará automaticamente uma chamada para o construtor sem
parâmetros da superclasse. Isso garante que todas as classes ancestrais sejam
construídas corretamente:

Packages e Import
Os pacotes são usados para evitar conflitos de nomenclatura e organizar
arquivos de código em diretórios diferentes. Para atribuir um arquivo de código
a um pacote – por exemplo, mypackage - ele deve ser movido para uma pasta com
esse nome, no diretório do projeto. Além disso, o arquivo deve especificar a
qual pacote ele pertence usando a palavra-chave do pacote seguida pelo nome do
pacote (e caminho).
Pode haver apenas uma instrução de pacote em cada arquivo de origem e deve ser
a primeira linha do código, exceto para quaisquer comentários. Observe que a
convenção de nomenclatura para pacotes é toda em letras minúsculas:

Os pacotes podem ter qualquer número de níveis de diretório de profundidade e


os níveis na hierarquia são separados por pontos. Por exemplo, se a pasta
mypackage que contém o arquivo de código for colocada em uma pasta de projeto
chamada sub, a declaração do pacote precisará ter a seguinte aparência:

Acessando pacotes
Para ilustrar como acessar os membros do pacote, um arquivo chamado
MyClass.java é colocado na pasta sub \ mypackage no diretório de origem do
projeto. O arquivo contém uma única classe pública chamada MyClass:

MyClass pode ser acessado de outro arquivo de origem de duas maneiras. A


primeira maneira é digitar o nome totalmente qualificado:

A segunda opção é encurtar o nome totalmente qualificado, incluindo a classe


com a palavra-chave import. Uma instrução de importação deve estar localizada
após a instrução de declaração do pacote e antes de todos os outros membros no
arquivo de código. Não tem nenhum outro propósito além de liberar o programador
de ter que digitar o nome totalmente qualificado:

18
Além de importar uma classe específica, todos os tipos (classes ou interfaces)
dentro de um pacote podem ser importados usando um asterisco (*). Observe que
isso não importa nenhum sub pacote:

Uma terceira variação da instrução import é a importação estática, que importa


todos os membros estáticos de uma classe. Depois que os membros estáticos são
importados, eles podem ser usados sem a necessidade de especificar o nome da
classe:

Níveis de Acesso
Existem quatro níveis de acesso disponíveis em Java: públic, protect, private e
package-private.

Private access
O nível de acesso mais restritivo é privado. Membros com este nível só podem
ser usados dentro da classe envolvente:

Acesso privado de pacote


Os membros privados do pacote podem ser acessados em qualquer lugar dentro do
pacote que o contém, mas não de outro pacote:

19
Acesso protegido
Os membros protegidos podem ser acessados em subclasses e no pacote que o
contém. Observe que o significado de protected em Java é diferente de outras
linguagens, como C ++ e C #, onde os membros protegidos são acessíveis apenas a
partir de subclasses e da classe contida:

Acesso público
O modificador public dá acesso irrestrito de qualquer lugar onde o membro pode
ser referenciado:

20
Acesso de nível superior
Os membros declarados diretamente no pacote ( package-private) podem escolher
apenas entre o acesso do pacote privado e público. Por exemplo, uma classe de
nível superior sem um modificador de acesso terá como padrão o pacote privado.
Essa classe só estará acessível dentro do pacote que o contém. Em contraste,
uma classe de nível superior explicitamente declarada como pública pode ser
alcançada de outros pacotes também:

Acesso de classe aninhada


Java permite que as classes sejam definidas dentro de outras classes, e essas
são chamadas de classes aninhadas . Essa classe pode ter qualquer um dos quatro
níveis de acesso. Se uma classe estiver inacessível, ela não pode ser
instanciada ou herdada:

Diretriz de nível de acesso


Como orientação, ao escolher um nível de acesso geralmente é melhor usar o
nível mais restritivo possível. Isso porque quanto mais lugares um membro pode
ser acessado, mais lugares ele pode ser acessado incorretamente, o que torna o
código mais difícil de depurar. Usar níveis de acesso restritivos também torna
mais fácil modificar a classe sem quebrar o código de qualquer outro
programador que use essa classe.

Constantes
Uma variável em Java pode ser transformada em uma constante adicionando a
palavra-chave final antes do tipo de dados. Este modificador significa que a
variável não pode ser reatribuída depois de definida e qualquer tentativa de
fazer isso resultará em um erro de tempo de compilação.

Constantes locais
Uma constante local sempre deve ser inicializada ao mesmo tempo em que é
declarada. A convenção de nomenclatura Java para constantes é usar todas as
letras maiúsculas e separar as palavras com sublinhados:

Campos constantes
Variáveis de classe e instância também podem ser declaradas como finais:

21
Em contraste com as constantes locais, os campos de constantes não precisam ser
atribuídos na declaração. Um campo de instância constante pode opcionalmente
ser atribuído em um construtor, e um campo estático constante pode ser
atribuído usando um bloco de inicialização estático. Essas atribuições
alternativas podem ser úteis se o valor da constante precisar ser calculado e
não couber em uma única linha de código:

Parâmetros de método constante


Outro lugar onde o modificador final pode ser aplicado é nos parâmetros do
método para torná-los inalteráveis. Isso fornece um sinal para outros
desenvolvedores de que o método não modificará o argumento transmitido a ele:

Constantes de tempo de compilação e de execução


Como a maioria das outras linguagens, Java tem constantes de tempo de
compilação e de tempo de execução. No entanto, apenas constantes de classe
podem ser constantes de tempo de compilação em Java, e somente se seu valor for
conhecido na compilação. Todos os outros usos de final criarão constantes de
tempo de execução. Com constantes de tempo de compilação , o compilador irá
substituir o nome da constante em todo o código por seu valor. Portanto, elas
são mais rápidas do que as constantes de tempo de execução, que não são
definidas até que o programa seja executado. As constantes de tempo de
execução, no entanto, podem receber valores dinâmicos que podem mudar de uma
execução de programa para a próxima:

22
Diretriz constante
Em geral, é uma boa ideia sempre declarar variáveis como final e campos
constantes como final estático, se eles não precisarem ser reatribuídos. Isso
garante que os campos e variáveis não sejam alterados por engano em qualquer
lugar do programa, o que por sua vez ajuda a prevenir bugs.

Interface
O tipo de interface é usado para especificar métodos que as classes que
implementam a interface devem definir. Esses métodos são criados com a palavra-
chave interface seguida por um nome e um bloco de código. A convenção de
nomenclatura é a mesma das classes: a primeira letra de cada palavra é
maiúscula:

Quando uma interface não está aninhada em outro tipo, seu nível de acesso pode
ser privado de pacote ou público, assim como qualquer outro membro de nível
superior .
Membros da interface
O bloco de código para uma interface pode, em primeiro lugar, conter
assinaturas para métodos de instância. Esses métodos não têm implementações. Em
vez disso, seus corpos são substituídos por ponto e vírgula. Os membros da
interface têm acesso público por padrão, então este modificador pode ser
deixado de fora:

O segundo membro que uma interface pode conter são constantes. Qualquer campo
criado em uma interface será declarado implicitamente como final estático,
portanto, esses modificadores também podem ser deixados de fora:

Além de assinaturas e constantes de método, uma interface também pode conter


tipos de conteúdo aninhados, como classes ou outras interfaces:

Exemplo de interface
O exemplo a seguir mostra uma interface chamada Comparable, que tem um único
método denominado compare:

23
A classe a seguir implementa essa interface usando a palavra-chave implements
após o nome da classe. Por convenção, a cláusula implements é colocada após a
cláusula extends se a classe tiver uma. Observe que embora uma classe só pode
herdar de uma superclasse, pode implementar qualquer número de interfaces,
especificando-as em uma lista separada por vírgulas:

Como o Circle implementa Comparable, ele deve definir o método de comparação.


Para esta classe, o método retornará a diferença entre os raios do círculo. O
método implementado deve ser público e deve ter a mesma assinatura do método
definido na interface:

Interface de funcionalidade
Comparable demonstra o primeiro uso de interfaces, que é definir uma
funcionalidade específica que as classes podem compartilhar. Torna possível
usar os membros da interface sem ter que saber o tipo real de uma classe. Para
ilustrar, o próximo exemplo mostra um método simples que pega dois objetos
Comparable e retorna o maior deles. Este método funcionará para qualquer classe
que implemente a interface Comparable porque o método usa apenas a
funcionalidade exposta por meio dessa interface:

Interface de classe
Uma segunda maneira de usar uma interface é fornecer uma interface real para
uma classe, por meio da qual a classe pode ser usada. O exemplo a seguir define
uma interface para MyClass chamada MyInterface. Essa interface inclui apenas a
funcionalidade de que os programadores que usam MyClass podem precisar:

24
O tipo de interface é então usado para manter a classe de implementação, de
forma que a classe só seja vista por meio desta interface:

Essa abstração oferece dois benefícios. Primeiro, torna mais fácil para outros
programadores usarem a classe porque agora eles só têm acesso aos métodos que
são relevantes. Em segundo lugar, torna a classe mais flexível porque sua
implementação pode mudar, sem ser perceptível por outros programadores usando a
classe, desde que a interface seja seguida.

Classes de interface
Conforme mencionado, uma interface pode conter tipos aninhados, como classes.
Em contraste com os métodos, esses tipos são implementados dentro da interface.
Isso pode, por exemplo, ser usado para fornecer uma classe que contém métodos
estáticos úteis para implementar classes. Esses tipos aninhados são visíveis
apenas para classes que implementam a interface, e não para objetos dessas
classes:

Métodos de interface
Esse método é especificado usando a palavra-chave padrão e pode incluir uma
implementação dentro da interface:

25
Um método padrão será usado, a menos que seja substituído por uma classe de
implementação. Isso fornece uma maneira compatível com versões anteriores de
adicionar novos métodos a uma interface sem quebrar as classes existentes que
usam a interface:

Outro recurso introduzido no Java 8 foram os métodos de interface


estática.Semelhante aos métodos de classe estática, esses métodos pertencem à
interface e só podem ser chamados a partir de um contexto de interface:

A partir do Java 9, os métodos estáticos podem ter acesso privado. Isso permite
que métodos padrão longos sejam divididos entre métodos privados, o que permite
menos
duplicação de código:

26
Abstract
Uma classe abstrata fornece uma implementação parcial sobre a qual outras
classes podem construir. Quando uma classe é declarada abstrata, significa que
ela pode conter métodos incompletos que devem ser implementados em subclasses,
além dos membros normais da classe. Esses métodos não foram implementados e
especificam apenas suas assinaturas, enquanto seus corpos são substituídos por
ponto-e-vírgulas:

Exemplo de classe abstrata


Se uma classe chamada Rectangle herda da classe abstrata Shape, Rectangle é
então forçado a substituir o método getArea abstrato. A única exceção é se
Rectangle também for declarado abstrato, caso em que não precisa implementar
nenhum método abstrato:

Uma classe abstrata não pode ser instanciada, mas pode ser usada para conter
instâncias de suas subclasses:

Mesmo que uma classe abstrata não possa ser instanciada, ela pode ter
construtores, que podem ser chamados a partir dos construtores da subclasse
usando a palavra-chave super:

27
Classes abstratas e interfaces
As classes abstratas são semelhantes às interfaces de várias maneiras. Ambos
podem definir assinaturas de método que as subclasses devem implementar e
nenhum deles pode ser instanciado. Uma diferença importante é que uma classe
abstrata pode conter qualquer membro abstrato ou não abstrato , enquanto uma
interface é limitada a membros abstratos, tipos aninhados e constantes
estáticas, bem como métodos estáticos e métodos padrão a partir do Java 8.
Outra diferença é que uma classe pode implementar qualquer número de
interfaces, mas apenas herdar de uma classe, abstrata ou não.
Uma interface é usada para definir uma funcionalidade específica que uma classe
pode ter ou para fornecer uma interface para outros desenvolvedores que usam
uma classe. Em contraste, uma classe abstrata é usada para fornecer uma
implementação parcial da classe, deixando que as subclasses a completem. Isso é
útil quando as subclasses têm alguma funcionalidade em comum, mas também têm
alguma funcionalidade que deve ser implementada de maneira diferente para cada
subclasse.
Enum
Uma enumeração , ou enum , é um tipo que consiste em uma lista fixa de
constantes nomeadas. Para criar um, a palavra chave enum é usada seguida por um
nome e um bloco de código contendo uma lista separada por vírgulas de elementos
constantes. O nível de acesso para um enum é o mesmo que para uma classe.
Pacote privado por padrão, mas também pode ser definido como público se for
declarado em um arquivo com o mesmo nome. Assim como acontece com as classes,
um enum pode estar contido em uma classe, onde pode ser definido para qualquer
nível de acesso:

Um objeto do tipo enum que acabou de ser mostrado pode conter qualquer uma das
quatro constantes definidas. As constantes enum são acessadas como se fossem
campos estáticos de uma classe:

A instrução switch fornece um bom exemplo de quando uma enumeração pode ser
útil. Comparado ao uso de constantes comuns, um enum tem a vantagem de permitir
que o programador especifique claramente quais valores constantes são
permitidos. Isso fornece segurança de tipo em tempo de compilação .
Observe que ao usar um enum em uma instrução switch, os rótulos de maiúsculas e
minúsculas não são qualificados com o nome do enum:

Classe Enum
Em Java, o tipo enum é mais poderoso do que suas contrapartes em outras
linguagens, como C ++ ou C #. Essencialmente um tipo especial de classe, pode
incluir qualquer coisa que uma classe possa incluir. Para adicionar um membro

28
da classe, a lista de constantes deve terminar com um ponto-e-vírgula e o
membro deve ser declarado após as constantes. No exemplo a seguir, um inteiro é
adicionado ao enum, que manterá a velocidade real que os elementos
representam:

Para definir este campo, um construtor também precisa ser adicionado. Um


construtor em um enum deve ter acesso privado ou privado de pacote e não é
chamado da mesma maneira que para uma classe regular. Em vez disso, os
parâmetros para o construtor são fornecidos após os elementos constantes, como
visto no próximo exemplo. Se um objeto Speed enum for atribuído à constante
SLOW, o argumento 5 será passado para o construtor dessa instância enum:

Outra diferença que os tipos enum têm quando comparados às classes regulares é
que eles se estendem implicitamente da classe java.lang.Enum. Além dos membros
herdados dessa classe, o compilador também adicionará automaticamente dois
métodos estáticos à enumeração, a saber, values e valueof. O método de valores
retorna uma matriz dos elementos constantes declarados no enum, e valueof
retorna a constante de enum do nome do enum especificado:

Manipulação de exceção
O tratamento de exceções permite que os programadores lidem com situações
inesperadas que podem ocorrer em seus programas. Por exemplo, a classe
FileReader no pacote java.io é usada para abrir um arquivo. A criação de uma
instância desta classe fará com que o Netbeans forneça um lembrete de que o
construtor da classe pode lançar uma FileNotFoundException. A tentativa de
executar o programa também fará com que o compilador aponte o seguinte:

29
Try-catch
Para lidar com esse erro de tempo de compilação, a exceção deve ser detectada
usando uma instrução try-catch . Esta instrução consiste em um bloco try
contendo o código que pode causar as exceções e uma ou mais cláusulas catch. Se
o bloco try for executado com sucesso, o programa continuará em execução após a
instrução try-catch , mas se ocorrer uma exceção, a execução será então passada
para o primeiro bloco catch capaz de lidar com esse tipo de exceção:

Catch block
No exemplo anterior, o bloco catch é definido apenas para manipular a
FileNotFoundException. Se o código no bloco try pudesse lançar mais tipos de
exceções, e todos eles devessem ser tratados da mesma maneira, uma exceção mais
geral pode ser capturada, como a própria classe Exception da qual todas as
exceções derivam. Essa cláusula catch seria então capaz de lidar com todas as
exceções que herdam dessa classe, incluindo FileNotFoundException. Tenha em
mente que uma exceção mais geral precisa ser capturada após uma exceção mais
específica. A cláusula catch deve sempre definir um objeto de exceção. Este
objeto pode ser usado para obter mais informações sobre a exceção, como uma
descrição da exceção usando o método getMessage:

A partir do Java 7, várias exceções de diferentes tipos podem ser capturadas


usando um único bloco catch. Isso ajuda a evitar a duplicação de código, sem
ter que capturar um tipo de exceção excessivamente geral, nos casos em que
múltiplas devem ser tratados da mesma maneira. Cada exceção é separada por uma
barra vertical (|) na cláusula catch:

Finally block
Como a última cláusula em uma instrução try-catch , um bloco finally pode ser
adicionado. Este bloco é usado para limpar recursos alocados no bloco try e
sempre será executado independentemente de haver ou não uma exceção. Neste
exemplo, o arquivo aberto no bloco try deve ser fechado, mas somente se foi
aberto com sucesso. Para poder acessar o objeto FileReader da cláusula finally,

30
ele deve ser declarado fora do bloco try. Além disso, como o método close
também pode lançar uma exceção, o método precisa ser cercado por outro bloco
try-catch . Lembre-se de que, se você esquecer de fechar um objeto de recurso,
o coletor de lixo do Java acabará fechando o recurso para você, mas fechá-lo é
uma boa prática de programação:

Java 7 adicionou a capacidade de fechar objetos de recurso automaticamente,


definindo o objeto de recurso entre parênteses após a palavra-chave try. Para
que isso funcione, o recurso deve implementar a interface
java.lang.AutoClosable. Essa interface consiste apenas no método close, que é
chamado automaticamente em uma instrução finally implícita. O exemplo anterior
agora pode ser simplificado da seguinte forma:

Mais de um objeto de recurso pode ser incluído para fechamento automático. A


partir do Java 9, os objetos declarados fora dos parênteses também podem ser
referenciados, desde que sejam finais ou efetivamente finais:

31
Throwing exceptions
Quando ocorre uma situação da qual um método não pode se recuperar, ele pode
gerar sua própria exceção para sinalizar ao chamador que o método falhou. Ele
faz isso usando a palavra-chave throw seguida por uma nova instância de um tipo
Throwable:

Exceções marcadas e desmarcadas


As exceções em Java são agrupadas em duas categorias - marcadas e desmarcadas -
dependendo se precisam ou não ser especificadas. Um método que lança uma
exceção verificada - por exemplo, IOException - não compilará a menos que seja
especificado usando uma cláusula throws após a lista de parâmetros do método e
o método de chamada captura a exceção. Por outro lado, exceções não
verificadas, como ArithmeticException, não precisam ser capturadas ou
especificadas. Observe que para especificar várias exceções, os tipos de
exceção são separados por uma vírgula:

Hierarquia de exceção
Exceções, como quase tudo em Java, são classes que existem em uma hierarquia.
Na raiz dessa hierarquia (abaixo de Object) está a classe Throwable, e todos os
descendentes dessa classe podem ser lançados e pegos. Herdadas de Throwable
estão as classes Error e Exception. As classes descendentes de Error são usadas
para indicar exceções não recuperáveis , como OutOfMemoryError. Eles não são
verificados porque, uma vez ocorridos, é improvável que o programador possa
fazer algo a respeito, mesmo que sejam pegos. Descendentes da Exceção estão as
RuntimeExceptions, que também estão desmarcadas. Essas são exceções que podem
ocorrer em quase qualquer código e, portanto, seria complicado capturá-las e
especificá-las. Por exemplo, uma divisão por zero lançará uma
ArithmeticException, mas cercar cada operação de divisão com um try-catch seria
incômodo. Também há alguma sobrecarga associada à verificação de exceções, e o
custo de verificar essas exceções supera o benefício de detectá-las. Os outros
descendentes de Exception, aqueles que não herdam de RuntimeExceptions, são
todos verificados. Essas são exceçõesque podem ser recuperadas e que devem ser
capturadas e especificadas.

Boxing e Unboxing
Colocar uma variável primitiva em um objeto é conhecido como boxing . O boxing
permite que o primitivo seja usado onde os objetos são necessários. Para este

32
propósito, Java fornece classes de wrapper para implementar boxing para cada
tipo primitivo
Byte, Short, Integer, Long, Float, Double, Character e Boolean. Um objeto
Integer, por exemplo, pode conter uma variável do tipo int:

O oposto de boxing é, naturalmente, unboxing , que converte o tipo de objeto de


volta em seu tipo primitivo:

As classes de wrapper pertencem ao pacote java.lang, que é sempre importado. Ao


usar objetos de invólucro, lembre-se de que o operador igual a (==) verifica se
ambas as referências se referem ao mesmo objeto, enquanto o método igual é
usado para comparar os valores que os objetos representam:

Autoboxing and autounboxing


Java 5 introduziu autoboxing e autounboxing . Esses recursos permitem a
conversão automática entre primitivos e seus objetos wrapper:

Observe que este é apenas um açúcar sintático projetado para tornar o código
mais fácil de ler. O compilador adicionará o código necessário para encaixotar
e desencaixotar os primitivos para você, usando os métodos valueOf e intValue:

Diretriz primitiva e wrapper


Tipos primitivos devem ser usados quando não há necessidade de objetos. Isso
ocorre porque os primitivos são geralmente mais rápidos e mais eficientes em
termos de memória do que os objetos. Por outro lado, os wrappers são úteis
quando os valores numéricos são necessários, mas os objetos são obrigatórios.
Por exemplo, para armazenar valores numéricos em uma classe decoleção, como
ArrayList, as classes de wrapper são necessárias:

33
Lembre-se de que as conversões entre objetos primitivos e wrapper devem ser
mantidas baixas se a velocidade for importante. Há uma penalidade de desempenho
herdada
associada a qualquer operação de boxing e unboxing.

Generics
Genérico se refere ao uso de parâmetros de tipo, que fornecem uma maneira de
definir métodos, classes e interfaces que podem operar com diferentes tipos de
dados. Os benefícios dos genéricos são que eles fornecem segurança de tipo em
tempo de compilação e eliminam a necessidade da maioria das conversões de tipo.
Classes genéricas
As classes genéricas permitem que os membros da classe usem parâmetros de tipo.
Tal classe é definida adicionando uma seção de parâmetro de tipo após o nome da
classe, que contém um parâmetro de tipo entre colchetes angulares. A convenção
de nomenclatura para parâmetros de tipo é que eles devem consistir em uma única
letra maiúscula. Normalmente, a letra T para tipo é usada. O exemplo a seguir
define uma classe de contêiner genérica que pode conter um único elemento do
tipo genérico:

Quando um objeto desta classe genérica é instanciado, o parâmetro de tipo deve


ser substituído por um tipo de dados real, como Integer:

Como alternativa, a partir do Java 7, uma classe genérica pode ser instanciada
com um conjunto vazio de parâmetros de tipo. Esse tipo de instanciação é
possível, desde que o compilador possa inferir (determinar) os parâmetros de
tipo do contexto:

Quando uma instância de MyBox é criada, cada parâmetro de tipo na definição de


classe é substituído pelo argumento de tipo passado . O objeto, portanto, se
comporta como um objeto regular, com um único campo do tipo Inteiro:

Observe que nenhuma conversão é necessária quando o valor armazenado é definido


ou recuperado do campo de caixa. Além disso, se o campo genérico for atribuído
por engano ou definido como um tipo incompatível, o compilador indicará que:

Métodos genéricos
Um método pode se tornar genérico, declarando-o com uma seção de parâmetro de
tipo antes do tipo de retorno do método. O parâmetro type pode ser usado como
34
qualquer outro tipo dentro do método. Você também pode usá-lo para o tipo de
retorno do método, na cláusula throws e para seus tipos de parâmetro. O próximo
exemplo mostra um método de classe genérico que aceita um parâmetro de matriz
genérico, o conteúdo do qual é impresso:

A classe mostrada acima não é genérica. Os métodos podem ser declarados como
genéricos, independentemente de a classe ou interface envolvente ser ou não
genérica. O mesmo é verdade para construtores.

Chamando métodos genéricos


Um método genérico é normalmente invocado apenas como um método regular (não
genérico) , sem especificar o argumento de tipo:

Na maioria dos casos, o compilador Java pode inferir o argumento de tipo de uma
chamada de método genérico, portanto, ele não precisa ser incluído. Mas se esse
não for o caso, o argumento de tipo precisará ser especificado explicitamente:

Interfaces genéricas
As interfaces que são declaradas com parâmetros de tipo tornam-se interfaces
genéricas. As interfaces genéricas têm os mesmos dois propósitos que as
interfaces regulares: elas são criadas para expor membros de uma classe que
será usada por outras classes ou para forçar uma classe a implementar uma
funcionalidade. Quando uma interface genérica é implementada, o argumento de
tipo deve ser especificado. A interface genérica pode ser implementada por
classes genéricas e não genéricas :

35
Parâmetros de tipo genérico
O argumento de tipo passado para um genérico pode ser um tipo de classe, tipo
de interface ou outro parâmetro de tipo, mas não pode ser um tipo primitivo. Os
genéricos podem ter mais de um parâmetro de tipo definido, adicionando mais
deles entre os colchetes angulares em uma lista separada por vírgulas.
Lembre-se de que cada parâmetro entre colchetes deve ser único:

Se um genérico tiver vários parâmetros de tipo definidos, o mesmo número de


argumentos de tipo precisa ser especificado quando o genérico é usado:

Usos de variáveis genéricas


Os genéricos são apenas uma construção de tempo de compilação em Java. Após o
compilador verificar se os tipos usados com variáveis genéricas estão corretos,
ele apagará todos os parâmetros de tipo e informações de argumento do código
genérico e inserirá as conversões apropriadas. Isso significa que os genéricos
não fornecem nenhum benefício de desempenho em relação ao código não genérico ,
por causa de casts de tempo de execução removidos, como fazem em, por exemplo,
C #. Isso também significa que os tipos genéricos não podem ser usados para
nada que requeira informações de tempo de execução - como a criação de novas
instâncias de tipos genéricos ou o uso do operador instanceof com parâmetros de
tipo. As operações permitidas incluem a declaração de variáveis do tipo
genérico, a atribuição de null a variáveis genéricas e a chamada de métodos
Object:

36
O processo de remoção de informações de tipo do código genérico é conhecido
como eliminação de tipo . Por exemplo, MyBox <Integer> seria reduzido a MyBox,
que é chamado de tipo bruto . Esta etapa é executada para manter a
compatibilidade com versões anteriores com o código escrito antes que os
genéricos se tornassem parte da linguagem em Java 5.

Parâmetros de tipo limitado


É possível aplicar restrições impostas em tempo de compilação nos tipos de
parâmetros de tipo com os quais um genérico pode ser usado. Essas restrições,
chamadas de limites , são especificadas na seção de parâmetro de tipo usando a
palavra-chave extends. Os parâmetros de tipo podem ser limitados por
superclasse ou interface. Por exemplo, a seguinte classe B só pode ser
instanciada com um argumento de tipo que seja do tipo A ou que tenha essa
classe como uma superclasse:

O próximo exemplo especifica uma interface como limite. Isso restringirá o


parâmetro de tipo apenas aos tipos que implementam a interface especificada ou
são do próprio tipo de interface:

Vários limites podem ser aplicados a um parâmetro de tipo, especificando-os em


uma lista separada por e comercial:

O e comercial atua como separador em vez de uma vírgula porque a vírgula já é


usada para separar os parâmetros de tipo:

Além de restringir o uso de um genérico apenas a certos tipos de parâmetro,


outro motivo para aplicar limites é aumentar o número de chamadas de método
permitidas com suporte pelo tipo limitado. Um tipo ilimitado só pode chamar os

37
métodos Object. No entanto, ao aplicar uma superclasse ou limite de interface,
os membros acessíveis desse tipo também ficarão disponíveis:

Generics and Object


Antes de os genéricos serem introduzidos no Java 5, o tipo Object era usado
para criar classes de contêiner que podiam armazenar qualquer tipo de objeto.
Agora que os genéricos estão disponíveis, esse uso do tipo Object como um
contêiner universal deve ser evitado. Isso ocorre porque o compilador ajuda a
garantir que os genéricos sejam seguros para o tipo em tempo de compilação, o
que não pode ser feito ao usar o tipoObject.
As classes de coleção da biblioteca Java, entre elas ArrayList, foram todas
substituídas por versões genéricas. Mesmo assim, qualquer classe genérica ainda
pode ser usada como se não fosse genérica, simplesmente deixando de fora a
seção de argumento de tipo. O tipo de objeto padrão será então usado como o
argumento de tipo. É por isso que a versão não genérica de ArrayList ainda é
permitida. Considere o seguinte uso de uma ArrayList não genérica :

Esta conversão de String para Inteiro falhará em tempo de execução, lançando


uma ClassCastException. Se um ArrayList genérico tivesse sido usado, a
conversão incorreta teria sido detectada na compilação ou imediatamente em um
IDE como o Netbeans. Este recurso de depuração em tempo de compilação é uma
grande vantagem com o uso de genéricos sobre outras abordagens de codificação:

38
Com a alternativa genérica, apenas o argumento de tipo especificado será
permitido na coleção ArrayList. Além disso, os valores obtidos da coleção não
precisam ser convertidos para o tipo correto, porque o compilador cuida disso.

Expressões Lambda
Java 8 introduziu a expressão lambda , que fornece uma maneira concisa de
representar um método usando uma expressão. Uma expressão lambda consiste em
três partes: uma lista de argumentos, o operador de seta (->) e um corpo. O
lambda a seguir recebe dois argumentos inteiros e retorna a soma deles:

Os tipos de parâmetro geralmente não precisam ser especificados porque o


compilador pode determinar esses tipos automaticamente. Essa inferência de tipo
também se aplica ao tipo de retorno. Se o corpo contiver apenas uma única
instrução, você pode omitir as chaves e o resultado da instrução será
retornado:

Objetos lambda
Uma expressão lambda é uma representação de uma interface funcional , que é uma
interface que define um único método abstrato. Ele pode, portanto, ser
vinculado a um objeto de tal interface, desde que seu método funcional tenha
uma assinatura correspondente:

Interfaces funcionais comuns são definidas no pacote java.util.function


adicionado em Java 8. Neste exemplo, a interface BinaryOperator <T> pode ser
usada. Ele representa um método que recebe dois argumentos e retorna um
resultado do mesmo tipo dos argumentos. Seu método funcional é denominado
aplicar:
39
Ao trabalhar em um único operando e retornar um valor do mesmo tipo, você pode
usar a interface funcional UnaryOperator. Observe que os parênteses em torno
dos parâmetros podem ser deixados de fora quando há apenas um parâmetro:

Parâmetros Lambda
Ao contrário dos métodos, as expressões lambda não pertencem a nenhuma classe.
Eles são objetos em si mesmos, pois são instâncias de interfaces funcionais. Um
benefício disso é que eles fornecem uma maneira conveniente de passar a
funcionalidade como um argumento para outro método. No exemplo a seguir, é
usada a interface Runnable, que possui um método funcional que não aceita
parâmetros e não retorna valor. Esta interface pertence a java.lang e seu
método abstrato é denominado run:

Você também pode obter essa funcionalidade definindo uma classe interna anônima
(sem nome), mas essa abordagem é consideravelmente mais detalhada do que a
expressão lambda:

Uma expressão lambda pode capturar variáveis de seu contexto, desde que a
variável referenciada seja final ou efetivamente final (apenas atribuída uma
vez). No próximo exemplo, a interface funcional do Consumidor é usada, que
representa uma função que aceita um parâmetro e não retorna nenhum valor:

40
Nos bastidores, o compilador irá instanciar uma classe anônima contendo um
único método para representar uma expressão lambda. Isso permite que lambdas
sejam totalmente compatíveis com versões anteriores do Java Runtime
Environment.

41

Common questions

Com tecnologia de IA

Inicialização tardia de campos estáticos em Java é realizada através de blocos de inicialização estáticos. Estes blocos são definidos no nível da classe e são executados uma única vez, no momento da inicialização do campo estático, permitindo executar lógica complexa necessitando múltiplas linhas antes que os campos estáticos sejam efetivamente utilizados. Tal abordagem garante que todos os preparativos necessários ao uso dos campos estáticos são realizados antes de sua utilização real .

Generics in Java improve type safety by allowing classes, interfaces, and methods to operate on specified types while preventing type cast exceptions at runtime. By specifying a type parameter, generics enable compile-time checks, ensuring that only the allowed types are used with the generic class or method. Unlike the use of Object, which requires casting and is prone to ClassCastException, generics eliminate most runtime errors related to type mismatches. However, generics are limited because they only exist at compile-time due to type erasure—generic type arguments are erased and replaced with their bounds or Object, limiting their use for runtime type creation and checks like 'instanceof' .

Lambda expressions, introduced in Java 8, enhance functional programming by allowing the implementation of functional interfaces in a more concise and readable manner. They consist of three core components: a list of formal parameters, the '->' arrow token, and a body (which can be an expression or a block of statements). Lambdas enable the simplification of code by removing boilerplate code typically associated with anonymous inner classes. By facilitating a functional style, they enable parallel and asynchronous programming constructs that align with modern programming requirements .

A palavra-chave 'default' é usada em métodos de interface para fornecer implementações padrão, permitindo que novas funcionalidades sejam adicionadas a interfaces sem obrigar as classes que as implementam a definir essas funcionalidades. Isso oferece uma maneira flexível e prática de evoluir interfaces e fornecer código reutilizável, pois as classes existentes não são obrigadas a alterar sua implementação quando uma interface é estendida com novos métodos .

Para declarar um método genérico em uma classe não genérica, você insere uma seção de parâmetro de tipo imediatamente antes do tipo de retorno do método. Esses parâmetros de tipo podem ser usados dentro do método, como em declarações de variáveis ou retorno do método. Métodos genéricos são invocados como métodos regulares; na maioria dos casos, o compilador Java infere o argumento do tipo. No entanto, se necessário, o argumento de tipo deve ser especificado explicitamente .

Static initialization blocks in Java are used to perform complex static variable initialization, executing only once when the class is first loaded into memory, unlike constructors which run each time an instance is created. These blocks are useful for setting up class-level resources that need initialization prior to any instance or static method usage. They provide an advantage over constructors by handling scenarios where initialization spans multiple steps or dependencies, thus ensuring that variables are ready for use the first time a class or its static context is accessed .

O operador 'instanceof' é útil para garantir a segurança ao realizar downcasting, verificando se um objeto é instância de uma classe específica antes de o lançar, para evitar exceções de tempo de execução. É particularmente indicado quando há necessidade de acessar métodos ou campos que pertencem à subclasse após ter trabalhado com a superclasse, certificando-se de que o objeto realmente suporta tal operação .

A palavra-chave 'this' é utilizada dentro de construtores para referenciar a instância atual da classe. Isso é especialmente útil quando os parâmetros de um construtor têm os mesmos nomes que os campos da classe, permitindo acessar os campos através de 'this'. Além disso, 'this' pode ser usado para chamar outros construtores da mesma classe, uma técnica conhecida como encadeamento de construtor, onde deve aparecer como uma chamada de método na primeira linha do construtor .

Genéricos em Java não suportam diretamente tipos primitivos, apenas tipos de classe. Isso é devido ao fato de que genéricos são implementados através de eliminação de tipo, funcionando apenas com referências de objeto. Para contornar essa limitação, tipos primitivos são autoboxed em suas contrapartes de classe, como int para Integer. Essa conversão permite que eles sejam usados em contextos de genérico, embora introduza alguma sobrecarga .

Interfaces genéricas permitem a criação de interfaces que podem operar sobre qualquer tipo de dado sem depender de tipos específicos, promovendo a reutilização e a flexibilidade do código. Além disso, o uso de genéricos proporciona segurança de tipo em tempo de compilação, reduzindo erros que só seriam detectados em tempo de execução ao usar tipos não genéricos, como Object .

Você também pode gostar