Introdução

Java é uma linguagem de programação de alto nível e orientada à objetos criada pela empresa Sun Microsystems no começo da década de 90. A sintaxe da linguagem é muito parecida com C e C++, mas ela possui um número maior de facilidades e funcionalidades.

Por exemplo, se o programa java for feito em uma plataforma Linux, ele pode ser usado na plataforma FreeBSD ou Windows - o programa rodará sem problema nenhum desde que a JRE (Java Runtime Environment), também conhecida como Máquina Virtual Java (Java Virtual Machine) esteja instalada na plataforma.

Linguagens como C e C++ rodam em diversas plataformas, mas os programas precisam ser recompilados, o que não acontece com o Java onde o mesmo binário pode ser portado. Além disso a linguagem pode ser usada para desenvolver programas para a maioria dos celulares, PDA's (Palm Tops) além de diversos dispositivos como cartões (Vale Refeição, Vale transporte, Cartões de acesso).

Por que aprender Java? editar

Dentre as características mais relevantes:

  • Java tem a filosofia 'WORA'

Uma das principais características de Java é o WORA (Write Once, Run Anywhere) ou simplesmente 'Escreva uma Vez e Execute em Qualquer Lugar'. Isso por si só traz vantagens, pois poupa tempo aprendendo bibliotecas específicas de Sistemas Operacionais. Poupa dinheiro, que seria gasto neste tempo. Poupa esforço, pois muitas vezes não há a necessidade de se conhecer alguns ou vários aspectos da plataforma subjacente.

  • Java possui "Coleta de Lixo" automática.

Isso significa que ela desaloca automaticamente qualquer espaço de memória não utilizado sem que o programador se preocupe com isso.

  • Java é uma linguagem de alto nível

Por ser uma linguagem de alto nível Java tem constructos e características que permitem escrever programas mais rapidamente do que em C/C++. Sendo assim há uma maior produtividade. Aliado ao fato de que Java sendo uma linguagem orientada a objetos, faz Java uma ótima escolha para desenvolvimento.

  • Java está presente em uma variedade de lugares

Os aplicativos Java estão presentes em diversas áreas, desde celulares, até servidores, o que dá ao desenvolvedor uma ampla gama de possibilidades de sistemas a serem desenvolvidos.

  • Java tem uma boa documentação, é gratuito e de código aberto

Como não há custo para se desenvolver em Java, pelo menos no início, há um incentivo aos novatos que não necessitam gastar com programas pagos, mas ao invés disso possuem escolhas de altíssima qualidade gratuitas e amplamente usadas.

Desvantagens da Linguagem editar

Apesar disso, a linguagem também possui as seguintes desvantagens:

  • Performance reduzida: por ser uma linguagem não projetada para gerar código nativo para cada arquitetura, os programas em Java costumam ter um desempenho menor que os escritos em linguagens como C++. Eles também costumam ocupar mais espaço em memória. Mas à medida que a linguagem vem sendo refinada, tal desvantagem vem diminuindo cada vez mais.
  • Programas em Java geralmente demoram mais tempo para compilar.
  • Programas que realizam cálculo com números em ponto flutuante tendem a possuir baixo desempenho.

Onde Java está presente? editar

Java está presente em todos os lugares, desde telefones celulares até TVs e computadores. A linguagem Java é uma das mais difundidas e conta com inúmeros recursos pela Web. Ela pode ser usada para criar aplicativos desktop, como por exemplo o Azureus e o Eclipse, aplicações web como applets, que rodam no lado cliente ou páginas JSP, e outros termos relacionados à sua versão EE, no lado do servidor. Além disso há padrões de TV digital que disponibilizam algum suporte a Java. Inclusive até há robôs que suportam Java, sendo o que o destaque vai para o da missão Mars Rovers que percorreu o solo lunar. Sendo assim java está disponível para um amplo espectro de aplicações, cada qual com sua utilidade e características próprias.

Por Onde Começar editar

Provavelmente você está ansioso para começar a aprender essa linguagem depois de tudo o que foi escrito até aqui, mas vamos com calma porque há ainda mais coisas a explicar e alguns conselhos a dar antes de realmente começarmos.

O primeiro é que a linguagem Java está disponível em várias versões, cada uma com seu propósito. Cada uma destas versões deve ser ressaltada uma vez que atuam em tecnologias diferentes e necessitam de diferentes pré-requisitos.

Java SE: É a tecnologia Java para desktops. É obrigatório o seu entendimento, ou pelo menos seus conceitos, pois serve de fundação para as outras versões. Atua em notebooks e PCs domésticos e está amplamente disponível, estando presente em quase 90% dos PCs do mundo.

Java ME: É a versão para dispositivos móveis, os quais geralmente têm menos memória sendo ela limitada bem como seu processamento também o sendo. Sendo assim nada mais é do que uma versão reduzida das APIs para desktop que incluem APIs específicas para construir aplicações que lidem com estas limitações.

JAVA EE: É na verdade um conjunto de especificações, as quais são implementadas em servidores de aplicação, tais como JBoss, Jetty, BEA Logic, etc. A base dela é o Java SE, porém o jeito de programar é diferente devido ao amplo conjunto de tecnologias e objetivos diferentes. Sendo assim o recomendado é aprender primeiro JavaSE, pois é a base para as outras edições. Para isso, como em qualquer linguagem, o ideal é primeiro treinar a lógica, pois o processo de desenvolvimento de programas requer o uso de lógica o tempo todo, e depois aprender Java em paralelo com o paradigma da orientação a objetos, o qual é o mais usado atualmente.

Para aprender Java, portanto, siga para os próximos passos para poder começar aprender os básicos dessa linguagem. Infelizmente não vamos poder ensinar a fundo a Orientação a objetos, já que este não é o foco principal do Wiki, e sim, ensinar Java.

Características de linguagens orientadas a objetos

Antes de aprender Java, é preciso conhecer quais são as características da Programação Orientada a Objetos (POO) que ela possui. Este capítulo tem por intuito mostrar a filosofia da POO para programadores não habituados à ela.

O que são Objetos editar

Em programação, objetos nada mais são do que um conjunto de dados sobre o qual estão definidas algumas operações. Se fôssemos criar um programa capaz de gerar na tela formas geométricas, por exemplo, poderíamos criar um objeto chamado "quadrado" que seria um conjunto de quatro números (que em POO são chamados de Atributos) que representam os seus vértices. O objeto "quadrado" poderia possuir as operações (que em POO são chamadas de Métodos) "MudaPosicao()" que serviria para posicionar o quadrado em uma coordenada específica passada como argumento e MudaCor() que trocaria a cor do quadrado desenhado na tela.

Os Atributos de um objeto são quaisquer variáveis que eles possuam que representam um número, caractere ou string. Se fôssemos programar um jogo, por exemplo, o personagem que o jogador controla poderia possuir atributos chamados Força, Resistência e Velocidade que seriam variáveis inteiras dentro do código. Ele também poderia possuir um atributo chamado Posição, que seria um vetor de inteiros que armazenariam a sua coordenada na tela.

Os Métodos de um objeto podem ser qualquer ação que o objeto pode executar. No jogo do exemplo acima, o personagem principal poderia possuir métodos chamados Pular, Atirar e Andar. Os Métodos nada mais são do que funções executadas sobre os Atributos de um Objeto.

Classes editar

Classes nada mais são do que uma declaração de um objeto no começo do código. Nesta declaração, você especifica quais são os Atributos e Métodos(Comportamentos)de seu objeto. Por exemplo, uma vez que você crie uma classe chamada "quadrado", você pode passar a criar novos objetos pertencentes à esta classe, que poderiam ter diferentes valores para cada um de seus Atributos.

Classe é um conjunto de especificaçãos técnica de um objeto, Nesta declaração, pode-se especificar quais são os Atributos e Metodos(Comportamentos) da classe. Por exemplo, uma vez que seja criada uma classe chamada "quadrado", pode-se passar a criar novos objetos pertencentes à esta classe, que podem ter diferentes valores para cada um de seus Atributos.

Herança editar

Herança é a capacidade que as classes tem de passar informações umas para as outras. Através da herança é possível criar fácil e rapidamente novos tipos de classes baseadas nas classes existentes. Por exemplo, assumindo que existe uma classe chamada "Veiculo", poderíamos gerar uma nova classe chamada "Carro", e outra classe chamada "Caminhao" que herdam (ou são filhas) de "Veiculo".

A classe "Veiculo" possui todos os Atributos que tem em comum entre um caminhão e um carro. Ambos possuem caracteristicas (Atributos) como, número de rodas, tipo de combustível, quantidade de portas, etc. Estes Atributos estão definidos na classe "Veiculo". Por sua vez, as classes "Carro" e "Caminhão", além de herdarem os atributos da classe "Veiculo", podem possuir seus próprios Atributos exclusivos. O mesmo ocorre com os Metodos.

Por exemplo, a classe "Caminhao", que poderia ter o Atributo numero de marchas reduzidas, que não faz sentido para um carro, apenas para um caminhão.

Para identificar se dois objetos tem uma relação de herança, deve-se analisar se o relacionamento é do tipo "é um tipo de". Por exemplo, Carro é um tipo de Veiculo, logo Carro herda de Veiculo; Cachorro é um tipo de Mamifero, e assim por diante.

Nota: em outras linguagens orientadas a objeto, como C++, existe herança múltipla, ou seja, uma classe pode herdar de mais de uma. Ex.: 'morcego é um tipo de mamífero' E 'morcego é um tipo de animal que voa'. Em java NÃO EXISTE herança múltipla! O que pode ser feito para simular isso é implementar uma Interface, mas isso será visto mais adiante.

Sobrecarga de métodos editar

Algumas vezes uma mesma operação pode ser feita de diversas maneiras, utilizando informações diferentes. Isso pode ser feito utilizando a sobrecarga de métodos. Consiste em criar mais de um método com o mesmo nome, porém com parâmetros de entrada diferentes. Isso é muito usado quando uma função tem valores padrão. Cria-se um método que recebe 3 parâmetros de entrada, e outro que não recebe nenhum, este ultimo irá invocar o primeiro passando os 3 valores padrão.

Sobreescrita de métodos editar

Quando a herança é usada, a classe 'filha' herda todos os métodos da classe 'pai', porém, as vezes isso pode trazer alguns problemas. Para dar mais flexibilidade, é possível sobreescrever um método, ou seja, criar uma nova implementação daquele método para a classe filha.

Polimorfismo editar

Poli (muitas) morphos (formas) permite ao desenvolvedor utilizar uma mesma assinatura de método para desempenhar funções similares, de acordo com o contexto. Um exemplo de polimorfismo no exemplo utilizado na herança seria um método que retorna a autonomia do veículo. No carro, este método tem que verificar a potência do motor e o combustível usado (alcool ou gasolina) no caminhão, teria que verificar o peso da carga e a potência do motor.

A vantagem do polimorfismo está no fato que um trecho de código, muitas vezes não sabe se o objeto Veiculo é um caminhão ou um carro, bastando chamar o método que retorna a autonomia, se o objeto for um carro, a virtual machine invoca o método do carro, se o objeto for um caminhão, ela invoca o método do caminhão.

Associação editar

Uma associação define uma relação entre duas classes que permite com que um objeto de uma classe utilize objetos de outra classe. Exemplo: Uma classe Motorista possui uma associação com a classe Volante, visto que objetos da classe Motorista vão utilizar objetos da classe Volante . Agregação e composição são dois casos específicos de associação.

Agregação editar

A agregação é um relacionamento onde a classe A se relaciona com a classe B, de forma com que objetos da classe A utilizam objetos da classe B. No entanto, a existência dos objetos da classe B não depende da existência dos objetos da classe A. Exemplo: Um objeto da classe Estudante utiliza objetos da classe SalaDeAula, porém a existência dos objetos da classe Estudante não depende da existência dos objetos da classe SalaDeAula.

Composição editar

A composição é um relacionamento onde a classe A se relaciona com a classe B, de forma com que objetos da classe A utilizam objetos da classe B, e a existência dos objetos da classe B dependem da existência dos objetos da classe A. Exemplo: Um objeto da classe SalaDeEstar dependem de objetos da classe Casa.

Vantagens da Programação orientada à Objetos editar

  • Modularidade: Uma vez que um objeto é criado, ele pode funcionar independente do resto do programa. Ele pode ser aproveitado em outros programas ou substituído por algum outro objeto.
  • Encapsulamento: Uma vez que objetos são criados, você só precisa se concentrar em usá-los, sem se preocupar com os detalhes de sua implementação.

Desvantagens da Programação Orientada à Objetos editar

  • Alguns tipos de programas podem ficar mais difíceis de serem criados usando POO.
  • Por ser uma filosofia de programação de mais alto nível, os programas tendem a ser mais lentos.

Ver também editar

A história de Java

A história de Java editar

Java começou na verdade como um projeto na Sun que objetivava o estudo e a análise de interações entre dispositivos eletrônicos e computadores, não exatamente para o desenvolvimento de uma linguagem para aplicativos embarcados. Nesse tempo a linguagem tinha o nome-código Green e foi idealizada por James Gosling. Contudo, a Sun perdeu a disputa para uma outra empresa e o projeto Green estava marcado para ser descontinuado.

Entretanto, eis que surge algo novo, sim, uma nova palavra chamada internet. Com o advento em 1993 do web browser Mosaic e das páginas estáticas HTML a vida das pessoas sofreria uma mudança profunda, bem como a do projeto Green. Com o objetivo de tirar proveito desse mercado o projeto Green sofre algumas mudanças e adaptações, se chamando Oak e em 1995 é lançado com o nome Java. Tal nome adveio do evento que os idealizadores da linguagem descobriram que já havia uma linguagem chamada Oak e então ao tomar seus cafés tiveram a idéia de a chamar de Java em virtude de este ser o nome do local daonde o café era comprado, a qual era é pequena ilha na Indonésia.

Assim em 1995 a Sun faz a divulgação da linguagem no evento SunWorld e a disponibiliza oficialmente em 1996, ano da primeira JavaOne. Java foi lançada então, sendo uma linguagem de propósito geral, porém, num primeiro momento conhecida por seus applets que adicionavam interatividade às páginas Web, característica ainda inexistente na época, quando a existência do Flash ainda nem era pensada. De lá para cá a linguagem sofreu muitas mudanças e evoluiu se adaptando com o tempo e atingindo a enorme popularidade que tem hoje.

Pré-requisitos para acompanhar o livro

Este livro foi desenvolvido para quem já tem conhecimento prévio sobre lógica de programação e alguma noção sobre orientação à objetos. Se esta é a sua primeira experiência com programação, não é recomendado que continue neste livro! Antes estude os livros Introdução à programação e Programação Orientada a Objetos.

Os aplicativos necessários para a execução dos códigos apresentados neste livro são:

  • Um editor de texto simples como o Notepad no Windows e o gedit no Ubuntu (e demais distribuições com o Gnome como ambiente gráfico) para edição do código-fonte. Esses editores já estão incluídos nos respectivos Sistemas Operacionais. Pode-se também utilizar editores com realce de sintaxe como o Sublime Text, Atom, Notepad++ (apenas para Windows), entre outros.
  • JDK 8 para compilação e execução dos programas. Os passos para instalação serão abordados a seguir.
  • Algum emulador de terminal, tal como Prompt de comando no Windows e gnome-terminal no Ubuntu, para executar os comandos de compilação e execução do JDK.

Não é indicado o uso de IDEs (acrônimo de Integrated Development Environment, em tradução livre Ambiente de Desenvolvimento Integrado) para estudo deste livro. Os IDEs, tais como Eclipse, NetBeans, IntelliJ, entre outras, oferecem diversas automatizações que aumentam a produtividade do desenvolvedor ao mesmo tempo que inibe a necessidade de se entender alguns dos conceitos apresentados aqui.

Java Development Kit editar

Mais conhecido como JDK é, como a tradução sugere, um kit de ferramentas para desenvolvimento em Java. Nesse kit é encontrado o compilador javac, a máquina virtual JVM responsável por executar os bytecodes compilados, a ferramenta javadoc que converte os comentários apropriados em códigos-fonte em documentação HTML, entre outros.

A lista de todas as ferramentas disponíveis no JDK 8 é encontrada em aqui.

Instalação do JDK no Windows editar

  1. Acesse a página do Java em Oracle e selecione entre Windows x86 e Windows x64 para versões de 32 bits ou 64 bits do Windows, respectivamente.
  2. Baixe e execute o instalador.
  3. Configure as variáveis de ambiente PATH e CLASSPATH:

No Windows 9x editar

Adicione as seguintes linhas no final do arquivo AUTOEXEC.BAT:

 set PATH=%PATH%; C:\Program Files\Java\jdk1.6.0_01\bin;
 set CLASSPATH=.

Obs.: A localização da pasta dos arquivos Java ("C:\Program Files\Java\jdk1.6.0_01\bin;") deve ser mudada de acordo do lugar onde você instalou o JDK. Reinicie o computador.

No Windows XP editar

Vá ao Painel de controle - Sistema. Abra a aba da janela "Avançado" e clique no botão "Variáveis do sistema". Edite a variável PATH adicionando o caminho C:\Program Files\Java\jdk1.6.0_01\bin (ou a pasta de instalação dos executáveis Java - caso já exista outros caminhos configurados, deve-se separar esta inclusão com ponto-e-vírgula ; ). Reinicie o computador.

Instalação do JDK no em Distribuições baseadas no Ubuntu editar

Há 2 opções para instalação do JDK 8: OpenJDK (código aberto) e Oracle HotSpot (código proprietário).

OpenJDK editar

  1. Acesse a Central de programas do Ubuntu e busque por jdk.
  2. Na barra inferior, clique em Mostrar itens técnicos.
  3. Selecione openjdk-8-jdk e instale-o.

OU

Entre no terminal e digite o comando abaixo.

sudo apt-get install openjdk-8-jdk

Verifique se a instalação ocorreu com sucesso inserindo o seguinte comando.

javac -version

A saída deverá ser a seguinte. Sendo que o último número poderá variar de acordo com o último update disponível no repositório oficial do Ubuntu.

javac 1.8.0_60

Oracle HotSpot editar

Entre no terminal e adicione o repositório do WebUpd8 e instale o HotSpot com o seguinte comando.

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer

A verificação de sucesso da instalação se dá da mesma maneira que do OpenJDK.

Mais informações editar

Para mais detalhes sobre como instalar o Java no Linux, veja o tutorial encontrado no livro Linux para iniciantes, capítulo Linux para iniciantes/Instalando programas/Java.

Criando e executando o primeiro programa

Para criar o primeiro programa é necessário um editor de texto simples, para a digitação do código-fonte, e o JDK instalado. O procedimento para instalação do JDK é explicado no capítulo anterior.

Etapas editar

Etapa 1 editar

No editor de texto digite o código exibido abaixo.

public class Teste {
    public static void main(String[] args) {
        System.out.println("Alô mundo!");
    }
}

Salve o arquivo com o nome Teste.java.

Etapa 2 editar

Por meio do terminal entre no diretório onde está o arquivo Teste.java e digite:

javac Teste.java

Etapa 3 editar

E por fim, digite:

java Teste

Será exibido:

Alô mundo!

Explicações editar

Não se preocupe em decorar as informações desta seção pois elas serão revistas com maior profundidade nos capítulos correspondentes.

Etapa 1 editar

Na 1.ª etapa foi digitado o código-fonte em Java. Código-fonte, à grosso modo, é um conjunto de instruções legíveis por humanos, definidas em uma linguagem de programação, para determinar o que o programa deverá realizar.

A primeira linha do código-fonte utiliza a palavra-chave class para definir uma classe com o nome Teste. O modificador de acesso public, que precede class, não é obrigatório no código acima pois há apenas uma classe sendo definida. [1]

Palavras-chave são palavras que servem como instruções para a linguagem de programação. Essas palavras não devem ser utilizadas para definir identificadores (nomes) de classes e métodos.[2]

Classe é um recipiente de código. Seu corpo, também conhecido como bloco de instruções, é definido entre as chaves de abertura { e fechamento }. No código acima o corpo da classe Teste inicia na primeira linha e termina na última linha. Não definir uma classe com os delimitadores de bloco de instruções (colchetes) causa um erro de compilação.

Na segunda linha, temos o método public static void main(String[] args) dentro do corpo da classe Teste.

Método, conhecido em outras linguagens de programação como função, é subconjunto de instruções que pode ser reutilizado. Assim como as classes, métodos também tem um corpo. Não definir um método com os delimitadores de bloco de instruções (colchetes) causa um erro de compilação.

Os modificadores de acesso public e static e o tipo de retorno void do método main serão abordados no capítulo sobre métodos. Por ora, basta saber que eles são obrigatórios para a compilação do código-fonte. main é o nome do método e (String[] args) define sua lista de parâmetros. [3]

O método main sempre será definido dessa forma para que haja a inicialização do programa. A esses códigos que sempre devem ser repetidos chamamos de código boilerplate.

Dentro do corpo do método main há a instrução System.out.println("Alô mundo!");. O método println é executado através da referência out localizada na classe System. O método em questão recebe como argumento a String "Alô mundo!".

String é uma sequência de caracteres delimitada com um par aspas duplas ".

Argumento é um valor enviado ao método.[4] É possível alterar o argumento no método print para qualquer outra String.

O código dentro da classe está espaçado em 4 colunas e dentro do método main em 8. A esse espaçamento damos o nome de indentação. A indentação não é obrigatória para o funcionamento do programa, mas é uma boa prática, pois aprimora a legibilidade do código. As instruções inseridas dentro de um bloco de instruções são espaçadas em relação ao próprio bloco. No caso de haver um bloco dentro de um bloco então as instruções dentro do bloco mais interno serão espaçados em 2 níveis. Neste livro é utilizado espaçamento de 4 colunas para cada nível, porém pode-se utilizar qualquer quantidade. É comum que ao invés de espaçamento sejam utilizadas tabulações para definir a indentação.

O nome do arquivo deve ser o mesmo da classe acompanhado da extensão .java.[5] Java é case-sensitive o que significa que diferencia letras maiúsculas de minúsculas. Logo, alterar a caixa de algum caracter de Teste.java resulta em erro.

Referências

  1. Os modificadores de acesso de classe serão vistos no capítulo Declaração de Classes.
  2. Regras adicionais no capítulo Identificadores.
  3. Também pode ser utilizado String... args.Mais sobre varargs no capítulo Métodos.
  4. Também a construtores e anotações.
  5. Apenas no caso da classe ser precedida do modificador public. Mais informações no capítulo Declarações de Classes.

Etapa 2 editar

No terminal é utilizado o comando javac Teste.java para compilar as instruções do código-fonte Teste.java em instruções de bytecode do arquivo Teste.class.

javac é o compilador incluído no JDK. Com ele é possível compilar os códigos-fontes .java em arquivos bytecode de extensão .class. No exemplo, o javac após compilar Teste.java produziu o bytecode Teste.class.

bytecode é um arquivo que contém instruções interpretáveis pela JVM (máquina virtual Java). Um bytecode pode ser executado em qualquer Sistema Operacional que contenha uma JVM, o que significa que se um código-fonte é compilado pelo javac em um Windows, teoricamente esse bytecode resultante poderá ser executado pelo comando java em um Ubuntu.

Etapa 3 editar

O bytecode é executado pela JVM ao comando java Teste ser disparado.

O comando java inicia a JVM, que por sua vez irá carregar o bytecode apontado no comando, no caso Teste, irá procurar pelo método main, e caso encontrado, a JVM irá executá-lo.

Ao utilizar o comando java deve-se digitar o bytecode sem a extensão .class. Caso a extensão seja utilizada, o seguinte erro será reportado por java.

java Teste.class
Erro: Não foi possível localizar nem carregar a classe principal Teste.class

Conveções utilizadas neste livro editar

  • Os códigos-fonte e as saídas de texto (mensagens resultantes no terminal) serão dispostos em caixas cinzas como abaixo.
public class Teste {
    public static void main(String[] args) {
        System.out.println("Exiba isto.");
    }
}
Exiba isto.


  • As saídas de texto tanto podem conter resultados de métodos como print quando o programa é compilado e executado com sucesso (como ocorreu acima) quanto podem apresentar erros de compilação, rastreamento de pilha de exceções e erro na chamada de comandos da JDK tal como java.

Erro apontado na compilação.

Teste.java:1: error: class Test is public, should be declared in a file named Test.java
public class Test {}

Rastreamento de pilha de exceção (do original em inglês: exception stack trace).

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Teste.main(Teste.java:3)

Erro na sintaxe de comando.

javac: invalid flag: Teste.class
Usage: javac <options> <syntaxhighlight files>
use -help for a list of possible options


  • Exceto quando descrito o contrário, todos os códigos ao longo dos próximos capítulos foram escritos dentro do corpo do método main.
System.out.println(42);
42


  • Os números iniciando cada linha do código-fonte servem apenas para ser referenciados no texto, não devendo ser digitados.
System.out.println(42);


  • Os conceitos apresentados serão destacados em amarelo.
System.out.print("A resposta para a pergunta essencial é: ");
System.out.printf("%d\n", 42);


  • Comentários contêm informações importantes sobre o código apresentado.
//Classe e método main omitidos.
System.out.print("A resposta para a pergunta essencial é: ");


  • No texto, referências às palavras-chaves serão apresentadas em caixas cinzas em linha como em class. Os identificadores (nomes) de métodos, classes e similares estarão em negrito como em "método main".

Exercícios editar

1

class Teste {public static void main(String[] args) { System.out.println("Testando."); } }


O código acima compilará?

Sim, se usado javac Teste.bytecode.
Sim, se usado javac Teste.java.
Sim, se usado javac Teste.class.
Sim, se usado javac Teste.
Não, apenas se indentado funcionaria.

2

public classe {
    static void main(String[] args) { 
        System.out.println("Alguma mensagem...");
    }}
O código acima compilará?

Sim, se usado javac classe.bytecode.
Sim, se usado javac Classe.class.
Sim, se usado javac classe.java.
Não, está faltando a palavra-chave class.
Não, o nome da classe tem que começar em maiúscula.

3

java Teste.classe

O comando acima executaria?

Sim, sem nenhuma modificação.
Sim, com a extensão .java.
Sim, com a extensão .bytecode/code>.
Não, pois não deve haver extensões.
Não, a extensão deveria ser class.


Como funciona o primeiro programa

1          public class OlaMundo {
2           public static void main(String[] args) {
3             System.out.println("Olá Mundo");
4           }}

A classe OlaMundo é criada(linha 1) com o método main(linha 2) que tem dois parâmetros, o Array String que terá os argumentos colocados no terminal e os args que terá o número de argumentos que foi passado.

A linha 3 pode ser explicada da seguinte forma, temos a classe System com a váriavel de instância out (que no caso é um objeto) referenciada e está variável de instância tem um método chamado println (Um método nada mais é do que uma função).

Tipos de dados primários

Tipos de dados primários editar

Toda variável deve ter um tipo de dado, pois, o tipo determina que valores a variável poderá conter e que operações poderão ser realizadas com ela.
Os tipos primários ou primitivos são os tipos de informações mais usuais e básicas. As variáveis deste tipo contêm valores simples, apropriados ao tipo da variável, e seus dados podem ser classificados basicamente em três categorias: lógicos, numéricos (inteiros e reais) e de caracteres.

Tipos de dados lógicos editar

boolean editar

É o tipo de dado que contém literal lógico. Serve para armazenar um único bit de informação. Este bit pode ser representado pelas palavras false (falso) ou true (verdadeiro). Representa estados binários, tais como: verdadeiro/falso, certo/errado, ligado/desligado, aberto/fechado, sim/não etc.
Exemplos de declarações:
boolean c;
boolean ligado = false;

Observação: um erro muito comum para quem programa em C/C++ é fazer testes lógicos usando variáveis inteiras ou reais. Em Java, a instrução if() só deve receber argumentos lógicos.

Tipos de dados numéricos editar

Tipos de dados numéricos inteiros editar

byte editar
É o tipo de dado capaz de armazenar 8 bits de informação, ou seja, um número inteiro entre -128 e 127. Sua utilização é recomendada em caso de economia de memória, já que alguns tipos de dados maiores possuem processamento mais rápido.
Exemplos de declarações:
byte a;
byte b = '1';
byte z = 111;
byte pato = 0xA;
byte seven = 07;
short editar
É o tipo de dado que é capaz de armazenar números inteiros de 16 bits, ou seja, um número inteiro entre -32.768 e 32.767.
Exemplos de declarações:
short a;
short by1 = -32;
short by2 = 0xBB;
int editar
É o tipo de dado capaz de armazenar 32 bits, ou seja, de representar um número inteiro qualquer entre -2.147.483.648 e 2.147.483.647. É o tipo mais indicado na maioria dos casos por possuir uma grande faixa de valores. Variáveis deste tipo também costumam ser manipuladas mais rapidamente já que correspondem à largura de dados (de palavra) mais usual na maioria dos processadores atuais.
Exemplos de declarações:
int a;
int by1 = -32;
int by2 = 0xBB;
long editar
É o tipo de dado capaz de armazenar 64 bits de informação, ou seja, que pode representar um número inteiro qualquer entre -9.223.372.036.854.775.808L e 9.223.372.036.854.775.807L. Recomenda-se seu uso apenas quando for preciso assumir valores maiores ou menores do que aqueles possíveis de serem assumidos pelo int.
Exemplos de declarações:
long a;
long bwy1 = -32L;
long byz2 = 32l;

Tipos de dados numéricos reais editar

float editar
É o tipo de dado capaz de armazenar números reais de precisão simples, ou seja, 32 bits de informação representando um número real.
Exemplos de declarações:
float a;
float by1 = -32.0;
float bz2 = 32.2F;
float bz = 32.455f;
float bze = 1.32455e4f;
double editar
É o tipo de dado capaz de armazenar números reais de precisão dupla, ou seja, 64 bits de informação em forma de número real. É usado para representar valores nos quais é preciso uma precisão maior que a de float.
Exemplos de declarações:
double a;
double by1 = -32.0;
double bz2 = 32.2d;
double bz = 32.455D;
double bze = 1.32455e4D;

Tipos de dados de caracteres editar

char editar

É o tipo de dado capaz de armazenar 16 bits representando caracteres no formato UTF-16 (formato UTF composto de dois caracteres de 8 bits). Representado numericamente, o tipo char pode ter valores de 0 a 65535 (inclusive) - de '\u0000' a '\uffff'. Nas versões mais recentes da linguagem Java, propõe-se substituir o tipo char pelo tipo byte.
Exemplos de declarações:
char letra = 'A' ;
char letra = '\u0041' ;

Literais

Literais editar

Literais são as representações de dados dentro do código fonte. Na linguagem Java, literais representam os dados dos tipos primitivos, dos tipos String e dos tipos nulo, por exemplo.
Assim, podemos subdividir os literais em:
  • Literais Booleanos ou Lógicos: correspondem ao valores true (verdadeiro) e false (falso).
  • Literais inteiros: representam os números inteiros e podem ser de base octal, decimal, ou hexadecimal. Assim:
    • Literais Inteiros Decimais: são números em base decimal que representam um valor inteiro. Eles podem ser tanto byte, como short, int ou long. Para escrever um literal inteiro na base decimal, basta digitar o seu valor com um desses dígitos: 0 1 2 3 4 5 6 7 8 9.
    • Literais Inteiros Octais: são números em base octal que representam um valor inteiro. Para representar este tipo de literal, basta escrever os seus dígitos colocando 0 (dígito zero) antes. Os dígitos para este tipo são: 0 1 2 3 4 5 6 7.
    • Literais Inteiros Hexadecimais: são números em base hexadecimal que representam um valor inteiro. Para representar este tipo de literal basta escrever os seus dígitos normalmente precedidos pelos caracteres 0x (zero xis) ou 0X. Os dígitos permitidos são: 0 1 2 3 4 5 6 7 8 9 A a B b C c D d E e F f.
  • Literais Fracionários (de Ponto Flutuante): correspondem aos números racionais (fracionários). Para representá-los, basta escrever um número inteiro seguido por um ponto e por sua parte decimal - o ponto faz o lugar da vírgula. Outra opção seria escrever o número em notação científica, escrevendo primeiro o valor da mantissa, seguido do caractere "e" e do valor do expoente (de base 10).
  • Literais Caracteres: correspondem a um caractere. Para representá-los, basta escrever o caractere cercado por apóstrofos. Também podem armazenar caracteres de controle de formatação (quebra de linha, etc.) e também caracteres no formato unicode.
  • Literais de cadeias de caracteres - Strings: correspondem às cadeias de caracteres. Para representá-los, escreva o(s) caracter(es) cercado(s) por aspas.
  • Literal nulo: representa a ausência de tipo e de dado (valor). Para representar utiliza-se a palavra null.
Os literais atribuem valores às variáveis ou partes do código. Ou seja, eles são usados para fazer com que variáveis passem a ter um valor ou se executem cálculos. Exemplos:
 boolean ligado=true;
 int velocidade=128;
 int x=0012;
 int peso=0x12a;
 float preco=1.24;
 char letra='f';
 int pesoTotal;
 pesoTotal=x*peso/4;
 String texto="Isto é um exemplo de cadeia de caracteres";

Nos exemplos acima, pudemos ver exemplos da atribuição de valores iniciais às diversas variáveis no momento da declaração assim como, a partir da declaração de pesoTotal (sem valor inicial), do cálculo de pesoTotal igual a x vezes o peso dividido por 4. A variável ligado recebe o valor "verdadeiro", velocidade recebe o número 128, x recebe 12 em octal que é o mesmo que 10 em decimal, peso recebe 12A em hexadecimal que é o mesmo que 298 em decimal, preco recebe 1,24 e letra recebe f. Já a variável texto recebe Isto é um exemplo de cadeia de caracteres.

Regras para representar literais fracionários (de ponto flutuante) editar

Regras básicas editar

  • Os literais do tipo float são representados colocando-se a letra F ou f após o número. Por exemplo:
 12f
 22F
Observação: é importante a utilização do F (ou f) após o número para representar o tipo float já que sua omissão implicará que o literal passe a ser automaticamente interpretado como sendo do tipo double. Por exemplo:
  • Os literais do tipo double são representados colocando-se a letra D ou d após o número.
 12d
 22D
  • A separação entre a parte inteira e fracionário do número é feita através do ponto - ao invés da vírgula. Por exemplo:
12.0f representa o número 12
22.23F representa o número 22,23
  • Caso a parte inteira seja 0 ("zero"), ela poderá ser omitida desde que se coloque o ponto (representando a vírgula) e a parte fracionária. Por exemplo:
.1f representa o número 0,1     
.0F representa o número 0

Outras variações de representação editar

Os literais fracionários também podem ser representados com o uso de uma exponenciação em base 10, ou seja, através do número seguido da letra e ou E seguido do expoente de base 10 a ser multiplicado e do f ou F. Exemplo:
1e3f representa o número  , ou seja, 1000
-1e3F representa o número  , ou seja, -1000
1e-2F representa o número  , ou seja, 0,01
-1e-3F representa o número  , ou seja, -0,001
Exista também a representação de literais fracionários em hexadecimal.
a fazer

Representação de caracteres de controle de texto editar

Caracteres de controle de texto podem ser representados da seguinte forma:
Código Significado
Escape Unicode
\b \u0008 caractere de retrocesso (backspace - BS)
\t \u0009 tabulação horizontal tab (horizontal tab - HT)
\n \u000a quebra de linha (linefeed - LF)
\f \u000c quebra de página (form feed - FF)
\r \u000d retorno de carro (carriage return - CR)
\" \u0022 aspas (double quote - " )
\' \u0027 apóstrofo (single quote - ' )
\\ \u005c barra invertida (backslash - \ )

Representação de caracteres no formato Unicode-16 editar

Unicode é padrão que define um conjunto de caracteres universais. O padrão Unicode-16 define caracteres com o uso de 2 bytes (16 bits). Na linguagem Java, define-se esses caracteres com \u seguido de 4 dígitos hexadecimais (dígitos 0 1 2 3 4 5 6 7 8 9 A a B b C c D d E e F f). Assim, a representação poderá variar de \u0000 até \uFFFF. Exemplos:
Caractere
Unicode-16
Caractere
gerado
\u7Fff 翿
\u7Ffc
\u0062 b
\u0078 x
Exemplo de declaração de uma variável do tipo char usando o literal Unicode-16:
 char letrax='\u0078';

Variáveis

Variáveis editar

Variáveis são nomes atribuídos à endereços na memória de um computador onde se guardam dados. A declaração de uma variável consiste em dar um nome para a posição de memória a ser usada e especificar qual tipo de dado a guardar na memória.
Para declarar uma variável, utiliza-se a seguinte sintaxe:
modificador tipo identificador;
Observação: o modificador é opcional no caso da variável ser a completar
Por exemplo:
 static int flor;
Pode-se declarar mais de uma variável do mesmo tipo separando-as por vírgulas, como na seguinte sintaxe:
modificador tipo identificador1, identificador2, identificador3;
Por exemplo:
 static float medida, raiz1, raiz2;
Iniciar uma variável é atribuir um valor, um dado, à variàvel. As variáveis também podem ser declaradas e iniciadas ao mesmo tempo. Por exemplo:
 static int tempodecorrido=0;

Modificadores editar

Identificadores editar

Identificadores

Identificador é o nome que utilizamos para representar as variáveis, classes, objetos, etc. Por exemplo, na Matemática utilizamos um nome para as incógnitas (x, y, z, etc.) que é o identificador daquela incógnita.
Utilizamos, em Java, as seguintes regras para criação do identificador:
  1. não pode ser uma palavra-reservada (palavra-chave);
  2. não pode ser true nem false - literais que representam os tipos lógicos (booleanos);
  3. não pode ser null - literal que representa o tipo nulo;
  4. não pode conter espaços em brancos ou outros caracteres de formatação;
  5. deve ser a combinação de uma ou mais letras e dígitos UNICODE-16. Por exemplo, no alfabeto latino, teríamos:
    • letras de A a Z (de \u0041 a \u005a);
    • letras de a a z (de \u0061 a \u007a);
    • sublinha _ (\u005f);
    • cifrão $ (\u0024);
    • dígitos de 0 a 9 (de \u0030 a \u0039).
Observação 01: caracteres compostos (acentuados) não são interpretados igualmente aos não compostos (não acentuados). Por exemplo, História e Historia não são o mesmo identificador.
Observação 02: letras maiúsculas e minúsculas diferenciam os identificadores, ou seja, a é um identificador diferente de A, História é diferente de história, etc.

Alguns exemplos de identificadores editar

X
abóbora
άγγελος
carro1
carro_1

Palavras-chave editar

Em programação, palavras-chave, ou palavras reservadas, são as palavras que não podem ser usadas como identificadores, ou seja, não podem ser usadas como nome de variáveis, nome de classes, etc. Estas palavras são assim definidas ou porque já têm uso na sintaxe da linguagem ou porque serão usadas em alguns momento, seja para manter compatibilidade com versões anteriores ou mesmo com outras linguagens. No caso do Java temos as seguintes palavras-chave:
abstract continue for new switch
assert(3) default goto(1) package synchronized
boolean do if private this
break double implements protected throw
byte else import public throws
case enum(4) instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp(2) volatile
const(1) float native super while
null

(1) sem uso na linguagem
(2) somente a partir da versão 1.2
(3) somente a partir da versão 1.4
(4) somente a partir da versão 5.0

Conversão de tipos

De String para tipo básico editar

int num = Integer.parseInt(numInt);
double num = Double.parseDouble(numDou);

Implícitas

Entre inteiros: tipos menores para tipos maiores;
byte b = 10; short s = 10; int i = 10; long l = 10;
s = b; i = b; i = s; l = b; l = s; l = i;
i = 10; l = 100;

Explícitas

Type Casting
varTipo1 = (tipo1) varOuValTipo2;

Entre inteiros: tipos maiores para tipos menores;

byte b = 10; short s = 10; int i = 10; long l = 10;
b = (byte) s; b = (byte) i; s = (short) i; b = (byte) l; s = (short) l; i = (int) l;
b = (byte) 10; s = (short) 10;

Cuidado para que o valor que está sendo atribuído não extrapole o tamanho máximo possível do tipo que está recebendo.

Constante

Constantes editar

As constantes em Java são declaradas através do modificador final. Um modificador de acesso também pode ser adicionado opcionalmente com o fim de determinar o escopo da constante. A sintaxe para declaração de uma constante é a seguinte:
 modificador final tipo identificador=literal;
Onde:
  • modificador = modificador de acesso (opcional);
  • tipo = tipo de dado primário;
  • identificador = nome (identificador) da constante;
  • literal = literal que atribui informação à constante.
Exemplo:
 public final int dez=10;
O exemplo acima cria uma constante pública (pelo modificador de acesso public) com o tipo de dado inteiro int com o valor 10.

Blocos e comentários de programação

Blocos de programação editar

Blocos de programação são aglomerados de instruções e declarações que têm escopo conjunto. Ou seja, as variáveis definidas como locais dentro de um bloco somente serão presentes dentro deste bloco assim como as instruções ali presentes. Os blocos de programação são delimitados por chaves e podem ser aninhados - colocados um dentro dos outros. Por exemplo:
{
   // este é um bloco de programação
   int a=10;
}
Outro exemplo:
{
   // este é um bloco de programação
   int a=10;
   int b=1;
   if (b==3) {
       // este é um bloco que é executado se b for igual a 3
       b=a*10;
   } else {
       // este é um bloco que é executado se b for diferente de 3
       int a=100;
       b=a*10;
   }
   System.out.println("O valor de b é " + b);
}

Comentários editar

Comentários, como o próprio nome instiga, são notas que podem ser incluídas no código fonte para descrever o que se quiser. Assim, não modificam o programa executado e servem somente para ajudar o programador a melhor organizar os seus códigos. Os comentários em Java seguem a mesma sintaxe da linguagem C++.

/* */ editar

Comentários de uma ou mais linhas podem ser iniciados por /* e terminados por */ . Por exemplo:
{
   int a=10;
   int b;
   b=a*2;
   /* a partir deste ponto, deve-se começar a exibir 
   os resultados na tela do usuário */
}

// editar

Comentários que terminam no final da linha são indicados com // . Pode ser usados desde o ínicio da linha ou colocados depois do código funcional, desde que não haja um caractere de quebra de linha no comentário. Por exemplo:
{
   int a=10; // declaração de a como int e atribuição do valor 10
   int b; //declaração de b
   // a próxima linha calcula b como sendo duas vezes a
   b=a*2;
   // daqui em diante deve-se exibir os resultados na tela
}

Comentários para facilitar a documentação automática editar

/** */ editar

Pode-se utilizar comentários de várias linhas em que a primeira linha se inicia com /** e a última termina com */. Ou seja, na seguinte sintaxe:
 //** Comentário
 * comentário
 * comentário
 * ...
 */
Observação: a documentação é gerada através do aplicativo javadoc.

Operadores

Operadores editar

Operadores são símbolos que representam atribuições, cálculos e ordem dos dados. As operações seguem uma ordem de prioridades, ou seja, alguns cálculos (ou outros) são processados antes de outros. Por exemplo, na Álgebra podemos mostrar a seguinte ordem:

Ordem Operadores Operação
1 /     *  Divisão e multiplicação
2 +     -  Soma e subtração

Assim, as operações de divisão e multiplicação, por serem de ordem 1, serão executadas antes das operações de soma e subtração (ordem 2). Também, as operações de divisão e multiplicação são de mesma ordem (1) e não importa, entre si, a ordem da operação (2 dividido por 4 vezes 9 é igual a 2 vezes 9 dividido por 4).

Tipo editar

Os operadores são divididos em 3 tipos em relação à quantidade de operandos no qual operam: unário, binário e ternário.

int a = 5, b = 2, c = 0;
a--;                   // -- é um operador unário pois opera apenas em a;
c = a * b;             // * é um operador binário pois opera em a e b.
c = c < 0 ? a : b;     // ?: é O operador ternário. Opera em na expressão booleana (c < 0), e em a ou b.

Precedência editar

Precedência indica a ordem na qual um operador opera em relação à avaliação de uma expressão.

A tabela seguinte elenca os operadores por precedência, do maior para o menor.

Tipo de Operador Lista de Operadores
Sufixais expr++ expr--
Prefixais ++expr --expr +expr -expr ~ !
Multiplicativos * / %
Aditivos + -
Shift Binário << >> >>>
Comparativos < > <= >= instanceof
igualdade == !=
Bit-aBit E &
Bit-aBit XOU OR ^
Bit-aBit OU OR |
Lógico E &&
Lógico OU ||
Ternário ? :
Atribuição = += -= *= /= %= &= ^= |= <<= >>= >>>=


Precedência 13: operadores sufixais editar

São operadores unários posicionados após o identificador da variável para incrementar ++ ou decrementar -- uma variável de tipo numérico em 1. Não podem ser utilizados em variáveis do tipo string, boolean ou de referência. Também não podem ser utilizados em valores de expressão e em literais. Diferente dos operadores de pré incremento/decremento, esses operadores sufixais retornam o valor original da variável para a expressão e depois realizam a operação sobre a variável.

int numero = 5;                        //A variável número é inicializada com 5.
System.out.println(numero++);          //É exibido 5, o valor original, e então a variável é atualizada para 6.
System.out.println(numero);            //É exibido 6, valor incrementado na instrução anterior.
5
6

Precedência 12: operadores prefixais editar

São operadores unários que alteram o valor de uma variável e seus sinais são posicionados antes do identificador da variável. Como exemplo, pode-se citar o Incremento ++, Decremento --, Sinal Positivo +, Sinal Negativo -, Inversão e Incremento ~ e Negação !. O incremento e decremento, já vimos o que faz. Eles estão sendo citados aqui novamente porque seus sinais podem vir antes de variáveis também e numa operação complexa (com outros operadores binários) alteram a precedência da operação. O Sinal Positivo + retorna a variável que vem depois dele com o mesmo sinal, o Sinal Negativo - inverte o sinal de variáveis transformando números positivos em negativo e vice-versa. Ele não pode ser usado em variáveis dos tipos boolean e char. O Incremento e Inversão ~ aumenta o número em uma unidade e inverte o seu sinal. Só pode ser usado em inteiros. Já a operação de negação ! transforma "verdadeiro" em "falso" e vice-versa, só podendo ser usado em variáveis do tipo boolean. Também só funcionam em variáveis, não em literais. Exemplos de uso:

 int numero=5;         //numero contém 5
 boolean ligado=false;   //ligado contém "falso"
 ++numero;             //numero agora vale 6 
 --numero;             //numero passa a valer 5
 numero=+numero;       //numero continua valendo 5
 numero=-numero;       //numero passa a valer -5
 numero=~numero;       //numero passa a valer 4
 ligado=!ligado;       //ligado passa a representar o valor "true"

Observação: uma diferença importante entre os operadores '++' e '--' prefixais e sufixais é o tempo de avaliação da expressão comparado com a alteração da variável. A saber:

 int x = 5;        // x contém 5
 int y, z;         // y e z não foram definidos
 y = x++;          // primeiro faz y igual ao valor (anterior) de x, e depois modifica x
 z = ++x;          // primeiro modifica x,  e depois atribui a z o novo valor de x

Neste exemplo, temos que, ao final x vale 7 (duas vezes incrementado), y vale 5 (o valor inicial de x) e z vale 7 (o valor final de x). Deve-se evitar usar mais de um operador prefixal e sufixal na mesma linha, porque isto torna o código incompreensível, por exemplo: x = (y++ + ++z - --x) + ++y.

Precedência 11: operadores multiplicativos editar

São operadores que realizam uma operação igual ou semelhante à multiplicação. Exemplos de operações do tipo são a Multiplicação (*), a Divisão (/) e o Resto (%). O primeiro pode realizar a multiplicação entre dois valores que não sejam do tipo boolean e nem do tipo char. O segundo pode dividir o primeiro número pelo segundo. Também não pode ser usado em valores booleans ou char. O terceiro retorna o resto da divisão do primeiro pelo segundo. Exemplos de uso:

 int numero=5;       //numero passa a valer 5
 numero=numero*4;    //numero assume o valor 20
 numero=200/numero;  //numero assume o valor 10
 numero=5%12;        //numero assume o valor 5

Precedência 10: operadores aditivos editar

São operadores que realizam alguma operação igual ou equivalente à adição. Assim como os Operadores Multiplicativos, os Aditivos podem ser usados tanto em variáveis como em literais (quando fazem a concatenação de strings). Mas também não podem ser usados em variáveis char e boolean. Eles também não alteram as variáveis passadas para eles. No lugar disso, eles retornam um número que deve ser direcionado par uma variável por meio da operação de atribuição (veja abaixo). Exemplos de uso:

 int numero=5;          //numero passa a valer 5
 numero=numero+8;       //numero passa a valer 13
 numero=numero-numero;  //numero passa a valer zero
 String x="Alo";        // x é inicializado com a string "Alo"
 String y="Mundo!";     // y é inicializado com a string "Mundo!"
 x = x + ", " + y;      // x passa a valer "Alo, Mundo!"

Precedência 9: operadores de shift editar

São operadores que deslocam os bits de um número de modo a alternar o seu valor. Exemplos de operadores deste tipo são o Shift para a Direita (>>), o Shift para a Direita Sem-Sinal(>>>) e o Shift para a Esquerda (<<). O primeiro valor a ser recebido pelo operador é o número sobre o qual será realizado um Shift e o segundo número é a quantidade de posições de bits a serem deslocados. Exemplos de uso:

 int numero=-3;        //numero vale -3
 numero=numero>>1;     //numero vale -2
 numero=numero<<1;     //numero vale -4
 numero=numero>>>1;    //numero vale 2147483646
 numero=numero<<1;     //numero vale -4

Precedência 8: operadores comparativos editar

São operadores que comparam dois números e retornam em seguido o valor booleano "verdadeiro" ou "falso". Como exemplo, pode-se citar o Menor que(<), Maior que (>), Menor ou Igual que(<=), Maior ou Igual que (>=) e Exemplo de (instanceof). O significado dos quatro primeiros operadores é evidente. Já a operação Exemplo de, retorna "verdadeiro" se o primeiro operando for um Objeto pertencente à classe passada como segundo operando e "falso" caso contrário. Exemplos de uso:

 boolean variavel;
 variavel=(4<4);   //variavel recebe "falso"
 variavel=(4<=4);  //variavel recebe "verdadeiro"
 variavel=(-1>-3); //variavel recebe "verdadeiro"
 variavel=(-4>=0); //variavel recebe "falso"

Precedência 7: operadores de igualdade editar

São semelhantes aos Operadores Comparativos. Eles também recebem números como operandos e retornam um valor boolean. A diferença é que estes operadores apenas verificam se as variáveis são iguais ou não. Como exemplos de operadores assim, pode-se citar o Igual a (==) e Diferente de (!=). Estes operadores podem ser usados em qualquer tipo de variável, desde que elas sejam do mesmo tipo. Exemplos de uso:

 boolean variavel;
 variavel=(-5==5);    //variavel recebe "falso"
 variavel=(2!=45674); //variavel recebe "verdadeiro"

Ao utilizar operadores de igualdade com objetos, a comparação é feita entre suas referências. Dessa forma, dois objetos cognitivamente iguais, podem ser avaliados como diferentes. Exemplo:

class Pessoa{
    String nome;

    public Pessoa(String nome){
        this.nome = nome; 
    }
}
new Pessoa("miguel") == new Pessoa("miguel") // comparação avaliada como falsa

Precedência 6, 5 e 4: operadores Bit-a-Bit editar

Os Operadores Bit-a-Bit são todos aqueles que realizam suas operações sobre os bits de um número, e não sobre o seu valor. Existem ao todo três destes operadores e cada um deles tem um valor de precedência diferente. O que tem precedência mais alta é o AND bit-a-bit (&). Ele analisa dois bits e retorna 1 se ambos forem iguais à 1 e 0 caso contrário. Depois vem o OR exclusivo bit-a-bit (^) que retorna 1 se os bits forem diferentes e 0 caso contrário. Por último, vem o operador OR inclusivo (|), que retorna 0 caso ambos os bits valerem 0 e retorna 1 caso contrário. Estes operadores podem ser usados em qualquer tipo de dados, desde que possuam o mesmo tamanho em bits. Exemplos de uso:

 int numero;
 numero=34&435;  //numero passa a valer 34
 numero=34^46;   //numero passa a valer 12
 numero=436|547; //numero passa a valer 951

Precedência 3 e 2: operadores AND e OR editar

Os operadores AND e OR só podem ser usados em variáveis e literais do tipo boolean. O operador AND (&&) retorna "verdadeiro" quando seus dois operandos também valem "verdadeiro" e retorna "falso" caso contrário. O operador OR (||) retorna "falso" quando seus dois operandos são falsos e retorna "verdadeiro" caso contrário. Exemplos de uso:

 boolean variavel;
 variavel=(2<45)&&(45<2)  //variavel passa a valer "falso"
 variavel=(2<45)||(45<2)  //variavel passa a valer "verdadeiro"

Precedência 1: operadores ternários editar

O operador ternário ? : recebe ao todo três operandos. O primeiro operando deve possuir necessariamente um valor do tipo boolean. Os outros dois operandos podem ser de qualquer tipo. Caso o valor do primeiro operando seja "verdadeiro", o operador retorna um valor igual ao do segundo operando. Caso o seu valor seja "falso", ele retorna um valor idêntico ao terceiro operando. Exemplos de uso:

 int numero1=245;
 int numero2=123;
 numero1=(numero1>numero2)?numero1:numero2; /* Faz com que a variavel numero 1 receba sempreo maior valor entre ela mesma e a numero2. Neste caso, ela
 receberá o seu prório valor por ele ser maior*/

Precedência 0: atribuições editar

Os operadores de atribuição são os mais numerosos e os que tem uma prioridade menor de serem interpretados. Um exemplo deste operador (=)foi bastante usado neste capítulo. Ele armazena o valor que aparecer à direita na variável presente à esquerda. Caso deseje-se que a variável da esquerda receba o valor dela mesma após passar por alguma operação com um segundo valor, basta colocar o símbolo da operação antes do sinal "=" e colocar o segundo valor à direita. Exemplos de uso:

 int numero = 3; //numero recebe o valor 3
 numero += 7;    //numero recebe 3+7. Ou seja, 10.
 numero -= 32;   //numero recebe o seu valor menos 32. Ou seja, -22.
 numero %= -3;   //numero recebe o resto da divisão entre seu valor e -3. Ou seja, -1.
 numero *= 6;    //numero recebe o seu valor vezes 6. Ou seja, -6.
 numero /= 2;    //numero recebe o seu valor dividido por 2. Ou seja, -3.

Quando em uma mesma linha forem encontrados vários operadores diferentes, serão executados primeiro aqueles que tiverem maior precedência. Se existirem operadores com o mesmo valor de precedência, será realizado primeiro aquele cujo símbolo aparecer primeiro. É possível alterar a ordem natural com que são feitas as operações através do uso de parênteses. As operações entre parênteses sempre são realizadas antes.


Separadores editar

Os separadores são sinais que separam, ou sejam, indicam/modificam a ordem das operações (ou atribuições, ou interpretações etc.) que podem ou não ser diferentes da comum. Em Álgebra, temos alguns separadores como os seguintes:
Ordem Separadores Descrição
1 , Vírgula
2 (     ) Parênteses
3 [     ] Colchetes
4 {     } Chaves

Separadores em Java editar

Ordem Separadores Descrição
1 ; Ponto-e-vírgula
1 . Ponto
1 , Vírgula
1 (     ) Parênteses
2 [     ] Colchetes
2 {     } Chaves

Ponto-e-vírgula, ponto e vírgula editar

O ponto-e-vírgula serve para separar sentenças ou instruções. A quebra de linha não separa instruções. Por exemplo:
 int 
 A;
É o mesmo que:
 int A;
E
 int A;
 float B;
É o mesmo que:
 int A; float B;
O ponto serve para separar a parte inteira da fracionária em um número, tal como na notação inglesa. Ou seja, enquanto escrevemos 2,5 para representar dois e meio, em Java escrevemos:
 2.5
A vírgula serve para separar itens, elementos, membros, como o que ocorre na atribuição de valores aos vetores, por exemplo:
 int[] vetor;
 vetor={34, 27, 3, 2};
 int JANELAS=10, PORTAS=4;
 class Casa implements Lavar, Pintar {
 }

Parênteses, colchetes e chaves editar

Na maioria das linguagens de programação de computadores, os separadores colchetes e chaves são utilizados para outros propósitos diferentes dos em Álgebra. Para uso semelhante, em programação se utiliza o aninhamento (inclusão dentro de outros) de parênteses. Por exemplo:
Em Álgebra:
{13x(4+12)/[12+(13+76/2)x(1+2)]+5}
Equivale a, em Java:
(13*(4+12)/(12+(13+76/2)*(1+2))+5)
Em Java, as chaves são utilizadas para separar blocos de programação e os colchetes são utilizados para indicar/separar os índices de vetores (e, também, na declaração dos mesmos vetores).

Outros separadores/delimitadores editar

Através de uma visão mais ampla, podemos encontrar muitos outros símbolos que podem atuar como separadores em Java.
Quando atuam em dupla, podem ser chamados de delimitadores, tais como:
  • aspas " " - são usadas para delimitar uma cadeia de caracteres;
  • apóstrofos ' ' - são usados para delimitar um literal do tipo caracter (char).
Alguns outros tipos de separadores:
  • e ou E - usados na notação científica de números fracionários;

Exercícios básicos

class Olamundo // declara a classe Olamundo que corresponde ao nome do programa {

   public static void main(String[] args) // declara o método principal (main)
       // que será executado ao iniciar a classe
   {
       System.out.println("Olá mundo!"); // escreve Olá mundo! na tela
   }

}

Comandos de seleção

Como pode-se notar, o conhecimento adquirido até aqui não permite a criação de programas interativos. Eles sempre executam da mesma forma, independente do que o usuário faz ou dos valores que são recebidos. Mas agora iremos aprender a usar alguns comandos que permitem que dependendo das circunstâncias, os programas executem instruções diferentes.

A instrução if editar

A instrução de seleção única if, também conhecida por if-then, possibilita a execução condicional de um bloco de instruções.

if (expressaoBooleana) {
    //instruções que serão executadas caso a expressaoBooleana resulte true.
}

Depois da palavra-chave if é necessária uma expressão booleana entre parênteses. Caso a expressão booleana resulte no valor true em tempo de execução então o bloco seguinte será executado, caso resulte em false aquele será ignorado. O bloco de instruções pode conter 0 ou mais instruções. As chaves que delimitam o bloco são opcionais caso se tenha apenas uma instrução a ser executada.

int hora = 20;
boolean eManha = false;

// Exemplo 1: com bloco.
if (hora <= 12) {
    eManha = true;
    System.out.print(hora + " AM");
}

//Exemplo 2: sem bloco.
if (!eManha)
    System.out.print(hora - 12 + " PM");
System.out.println(" é o mesmo que " + hora + " horas."); //Esta linha é incondicionalmente exibida
8 PM é o mesmo que 20 horas.

A instrução if...else editar

Também conhecida como instrução if-then-else, a instrução de seleção dupla if...else tem função complementar à de if: executa instruções no caso da expressão booleana de if resultar em false.

if (expressaoBooleana) {
    //instruções que serão executadas caso a expressaoBooleana resulte true.
} else {
    //instruções que serão executadas caso a expressaoBooleana resulte false.
}

A palavra chave else deve estar logo após da(s) instrução(ões) de if. Após a palavra chave else deve ser colocado o bloco de instruções a serem executadas no caso da expressão booleana de if resultar em false. Assim como if, as chaves delimitadoras de bloco são opcionais caso haja apenas uma instrução a executar.

int hora = 20;

if (hora <= 12) 
    System.out.print(hora + " AM");
else
    System.out.print(hora - 12 + " PM");
System.out.println(" é o mesmo que " + hora + " horas."); //Esta linha é incondicionalmente exibida
8 PM é o mesmo que 20 horas.

Instruções if...else aninhadas editar

As instruções if ou if...else podem ser aninhadas dentro de outras instruções if ou if...else para casos em que antes de determinadas instruções serem executadas sejam necessárias combinações de resultados de expressões booleanas.

if (expressaoBooleana1) {
    if (expressaoBooleana2) {
    // Instruções a serem executadas caso as expressões booleanas 1 e 2 resultem em true.
    } else {
    // Instruções a serem executadas caso a expressão booleana 1 resulte em true, e a 2 em false.
    }
} else {
     if (expressaoBooleana3) {
    // Instruções a serem executadas caso a expressão booleana 1 resulte em false, e a 2 em true.
    } else {
    // Instruções a serem executadas caso as expressões booleanas 1 e 3 resultem em false.
    }
}

As instruções if e if...else aninhadas não apresentam nenhum comportamento diferente do esperado caso não estivessem aninhadas. Estão sendo abordadas apenas com o intuito de exemplificar a possibilidade de aumento das ramificações de decisões.

int hora = 20;

if (hora < 0 || hora >= 24)
    if (hora < 0)
        System.out.print("Erro: A hora deve ser maior que 0.");
    else
        System.out.print("Erro: A hora deve ser menor que 24.");
else {
    if (hora <= 12) 
        System.out.print(hora + " AM");
    else
        System.out.print(hora - 12 + " PM");
    System.out.println(" é o mesmo que " + hora + " horas."); //Esta linha é incondicionalmente exibida
}

É possível verificar no exemplo acima que a primeira instrução if mesmo contendo mais de uma linha de instruções consegue identificar que o if...else forma uma única ramificação e assim executar a expressão booleana normalmente. Isso se deve ao fato que toda else está vinculada a uma if. Já na else com o escopo mais externo, verifica-se chaves delimitadoras de bloco. Essas chaves são necessárias por conta de uma segunda instrução, nomeadamente System.out.println(), que é executada independentemente do resultado da expressão booleana da if...else.

int hora = 20;

if (hora < 0)
    System.out.print("Erro: A hora deve ser maior que 0.");
else if (hora >= 24)
    System.out.print("Erro: A hora deve ser menor que 24.");
else if (hora <= 12) 
    System.out.print(hora + " AM é o mesmo que " + hora + " horas.");
else
    System.out.print(hora + " PM é o mesmo que " + hora + " horas.");
}

No exemplo acima há um recurso estilístico para indentar o código com a finalidade de aprimorar a legibilidade. As palavras chave if foram anexadas às palavras chave else já que as else têm somente uma instrução cada e por isso não necessitam de chaves para delimitar bloco de instruções. O código abaixo tem exatamente a mesma funcionalidade apesar das quebras de linha.

int hora = 20;

if (hora < 0) 
    System.out.print("Erro: A hora deve ser maior que 0.");
else 
    if (hora >= 24)
        System.out.print("Erro: A hora deve ser menor que 24.");
    else 
        if (hora <= 12) 
            System.out.print(hora + " AM é o mesmo que " + hora + " horas.");
        else
            System.out.print(hora + " PM é o mesmo que " + hora + " horas.");

A instrução switch editar

A instrução switch por vezes chamada de switch...case possibilita a execução condicional de instruções de acordo com a correspondência entre a expressão avaliada e a constante em case.

switch (expressao) {
    case constante1: 
        // Instruções
        break;
    case constante2: 
        // Instruções
        break;
    case default: 
        // Instruções
}

Dentro do parâmetro da switch pode ser utilizada expressão que resulte em: byte, short, char, int, String e enum. As chaves que delimitam o bloco são necessárias ainda que só haja uma ramificação do fluxo do código. A palavra chave case indica as ramificações de código. Deve ser seguida de uma expressão constante que corresponda ao tipo da expressão inserida no parâmetro da switch, e essa expressão constante, por sua vez, deve ser seguida de : que é o carácter que delimita o início do bloco de instruções relativo à case. Após : podem ser inseridas 0 ou mais instruções, incluindo a palavra chave break que será abordada mais adiante. Ao iniciar outra instrução case ou inserir a chave de fechamento do bloco de switch o bloco anterior é encerrado.

int dia = 5;
final int segunda = 2;
final int sexta = 6;

switch (dia) {
    case segunda:
        System.out.print("Segunda ");
    case 3:
	System.out.print("Terça ");
    case 4:
	System.out.print("Quarta ");
    case 5:
	System.out.print("Quinta ");
    case sexta:
	System.out.print("Sexta ");
    case 7:
	System.out.print("Sábado ");
    case 0:
    case 1:
	System.out.print("Domingo ");
}
Quinta Sexta Sábado Domingo 

Em tempo de execução, a variável dia será comparada com as expressões constantes, definidas em tempo de compilação, de cada case. O case contendo o valor 5 tem valor igual ao da variável dia, então desse ponto em diante todas as instruções serão executadas até que chegue o término do bloco de switch.

A instrução break editar

Caso seja necessário que apenas sejam executadas instruções vinculadas a determinadas case então deve-se utilizar a instrução break. Após a instrução break o fluxo do programa sai do bloco de switch.

int dia = 5;
final int segunda = 2;
final int sexta = 6;

switch (dia) {
    case segunda:
        System.out.print("Segunda ");
    case 3:
	System.out.print("Terça ");
    case 4:
	System.out.print("Quarta ");
    case 5:
	System.out.print("Quinta ");
    case sexta:
	System.out.print("Sexta ");
	break;
    case 7:
	System.out.print("Sábado ");
    case 0:
    case 1:
	System.out.print("Domingo ");
}
System.out.println("\n-> Fora do bloco de instruções de switch.");

Com a instrução break inserida no bloco da case com valor sexta, o código será executado da case com valor 5 até essa break referida.

Quinta Sexta 
-> Fora do bloco de instruções de switch.

A instrução default editar

A instrução default pode ser utilizada para o caso da expressão no parâmetro de switch não corresponder a nenhum dos valores das instruções case. default pode aparecer em qualquer ordem e segue o mesmo funcionamento que case no que tange a bloco de instruções e uso de break.

int dia = -5;
final int segunda = 2;
final int sexta = 6;

switch (dia) {
    case segunda:
        System.out.print("Segunda ");
    case 3:
	System.out.print("Terça ");
    case 4:
	System.out.print("Quarta ");
    default:
	System.out.println("erro: dia deve estar entre [0, 7]");
	break;  
    case 5:
	System.out.print("Quinta ");
    case sexta:
	System.out.print("Sexta ");
	break;
    case 7:
	System.out.print("Sábado ");
    case 0:
    case 1:
	System.out.print("Domingo ");
}
erro: dia deve estar entre [0, 7]

Exercícios editar

// Exercícios 1 e 2.
int a = 5;

if (a > 2)
    if (a < 4)
        System.out.println("a é igual a 3.");
else
    System.out.println("a é menor ou igual a 2.");

Dado o código acima, responda:

1. O que será impresso na tela? A afirmação está correta?
Será exibido a é menor que 2. porém a informação está incorreta. A instrução else está vinculada a if imediatamente anterior, e no parâmetro dessa if a expressão booleana resultará false. Logo, a informação correta seria a é maior ou igual a 4..
2. Como corrigir o código?
int a = 5;

if (a > 2) {
    if (a < 4)
        System.out.println("a é igual a 3.");
} else
    System.out.println("a é menor ou igual a 2.");
// Exercício 3.
double b = 10.5;
double c = 2.0;

if (b == c) 
    System.out.println("b é igual a c");
else if (b > c)
    System.out.println("b é maior que c");
else if (b < c)
    System.out.println("b é menor que c");

Dado o código acima, responda:

3. Remova o código desnecessário, defina blocos de instruções para todas as instruções if...else e indente.
A última expressão booleana (b < c) não é necessária pois caso um número b não seja maior ou igual a um número c, obviamente ele será menor.
double b = 10.5;
double c = 2.0;

if (b == c) {
    System.out.println("b é igual a c");
} else {
    if (b > c) {
        System.out.println("b é maior que c");
    } else {  
        System.out.println("b é menor que c");
    }
}

Comandos de iteração

Neste capítulo veremos como fazer para que o seu programa execute uma sequência de instruções um determinado número de vezes ou até que determinada condição seja satisfeita.

O comando for editar

O comando for deve ser usado sempre que se deseja que um código seja executado um determinado número de vezes. A sintaxe do comando for é:

 for(INICIALIZAÇÃO;CONDIÇÃO;EXPRESSÃO){
     COMANDO(S);
 }

Quando o comando "for" é executado, a primeira coisa a ser feita é a inicialização prevista. Em seguida, verifica-se se CONDIÇÃO é "falso". Em caso afirmativo, o loop não será executado. Caso contrário, todos os comandos existentes no bloco abaixo do comando são executados e a operação prevista em EXPRESSÃO é executada. Mais uma vez, a CONDIÇÃO é analisada. Caso ela seja falsa, o loop é interrompido. Caso contrário, ela continua. Exemplos de uso:

 for(int i=1;i<=10;i++)         //O loop é executado 10 vezes
     System.out.println(i+" "); //Será impressa na tela uma contagem de 1 até 10.

O comando while e do-while editar

O comando while deve ser usado sempre que não sabemos quantas vezes um loop será executado. A sintaxe do comando é:

 while(CONDIÇÃO){
     COMANDO(S);
 }

Quando o comando "while" é executado, verifica-se o valor retornado por CONDIÇÃO. Se for "verdadeiro", a sequência de comandos presente no bloco logo abaixo do comando é executada. Ao fim, o valor de CONDIÇÃO é verificado novamente. O loop só para quando o valor retornado por CONDIÇÃO for "falso".

Além do comando "while", também pode ser usado o comando "do-while" que segue a seguinte sintaxe:

 do{
     COMANDO(S);
 }while(CONDIÇÃO);

Ele funciona exatamente igual ao comando "while". A diferença é que a CONDIÇÃO só é analisada depois que os comandos são executados. Isso significa que o comando "do-while" sempre executa o conjunto de comandos ao menos uma vez. Mesmo que a condição seja inicialmente falsa. Exemplos de uso:

Exemplo 1:

 while(true){
     System.out.printls("Estou preso!"); //Como aqui CONDIÇÃO sempre é verdadeira, este comando sempre será executado.
 }

Exemplo 2:

 while(variavel%435==4){ 
      variavel+=(variavel*3);  //O numero de vezes que este comando será executado depende do valor inicial da variável
 }

Comandos de controle de fluxo editar

Existem alguns comandos que foram feitos para facilitar o uso de loops em programas. Eles permitem que você controle melhor o fluxo de execução de um programa. São eles:

O comando break editar

O comando break é um comando bastante importante no desenvolvimento da maior parte dos programas de computador, ele é usado para sair imediatamente de um laço (loop, em inglês), independente do valor de CONDIÇÃO. Ele pode ser executado dentro de um while, for, do ... while ou switch (estes comandos serão discutidos mais adiante neste livro), fazendo um saída imediata dessa instrução. Passando para o execução do próximo comando.

A sintaxe do comando é bastante simples:

 break;

Exemplos de uso: No exemplo abaixo temos um código escrito em Java, onde em um loop for é interrompido quando a variável inteira contador se torna igual a 5.

 public class BreakTeste
{
    public static void main( String args[] )
    {
    int contador; //Variável de controle usada como referência
   
    for ( contador = 1; contador <= 10; contador++ )//Laço, será repetido 10 vezes
        {
        if ( contador == 5 ) //Se o contador chegar até 5
            break;        //Termina o loop quando a condição do if se tornar verdadeira
       
        System.out.printf( "%d ", contador);
        }//Termino da instrução for
   
    System.out.printf( "\nInterrompe o contador quando o contador = %d\n",contador );
    }//Fim do main
}//Fim da classe BreakTest

O comando continue editar

O comando continue serve para encerrar a execução de comandos e verificar o valor de CONDIÇÃO. Caso o valor seja "verdadeiro", a iteração continua. Caso contrário, ela se encerra. Exemplos de uso:

 for(int i=1;i<=10;i++){        //O loop é executado 10 vezes
     if(i%2==0)
          continue;
     System.out.println(i+" "); //Será impressa na tela os números ímpares entre 1 e 10
 }


Neste capítulo veremos como fazer para que o seu programa execute uma sequência de instruções um determinado número de vezes ou até que determinada condição seja satisfeita.

O comando for editar

O comando for deve ser usado sempre que se deseja que um código seja executado um determinado número de vezes. A sintaxe do comando for é:

 for(INICIALIZAÇÃO;CONDIÇÃO;EXPRESSÃO){
     COMANDO(S);
 }

Quando o comando "for" é executado, a primeira coisa a ser feita é a inicialização prevista. Em seguida, verifica-se se CONDIÇÃO é "falso". Em caso afirmativo, o loop não será executado. Caso contrário, todos os comandos existentes no bloco abaixo do comando são executados e a operação prevista em EXPRESSÃO é executada. Mais uma vez, a CONDIÇÃO é analisada. Caso ela seja falsa, o loop é interrompido. Caso contrário, ela continua. Exemplos de uso:

 for(int i=1;i<=10;i++)         //O loop é executado 10 vezes
     System.out.println(i+" "); //Será impressa na tela uma contagem de 1 até 10.

O comando while e do-while editar

O comando while deve ser usado sempre que não sabemos quantas vezes um loop será executado. A sintaxe do comando é:

 while(CONDIÇÃO){
     COMANDO(S);
 }

Quando o comando "while" é executado, verifica-se o valor retornado por CONDIÇÃO. Se for "verdadeiro", a sequência de comandos presente no bloco logo abaixo do comando é executada. Ao fim, o valor de CONDIÇÃO é verificado novamente. O loop só para quando o valor retornado por CONDIÇÃO for "falso".

Além do comando "while", também pode ser usado o comando "do-while" que segue a seguinte sintaxe:

 do{
     COMANDO(S);
 }while(CONDIÇÃO);

Ele funciona exatamente igual ao comando "while". A diferença é que a CONDIÇÃO só é analisada depois que os comandos são executados. Isso significa que o comando "do-while" sempre executa o conjunto de comandos ao menos uma vez. Mesmo que a condição seja inicialmente falsa. Exemplos de uso:

Exemplo 1:

 while(true){
     System.out.printls("Estou preso!"); //Como aqui CONDIÇÃO sempre é verdadeira, este comando sempre será executado.
 }

Exemplo 2:

 while(variavel%435==4){ 
      variavel+=(variavel*3);  //O numero de vezes que este comando será executado depende do valor inicial da variável
 }

Comandos de controle de fluxo editar

Existem alguns comandos que foram feitos para facilitar o uso de loops em programas. Eles permitem que você controle melhor o fluxo de execução de um programa. São eles:

O comando break editar

O comando break é um comando bastante importante no desenvolvimento da maior parte dos programas de computador, ele é usado para sair imediatamente de um laço (loop, em inglês), independente do valor de CONDIÇÃO. Ele pode ser executado dentro de um while, for, do ... while ou switch (estes comandos serão discutidos mais adiante neste livro), fazendo um saída imediata dessa instrução. Passando para o execução do próximo comando.

A sintaxe do comando é bastante simples:

 break;

Exemplos de uso: No exemplo abaixo temos um código escrito em Java, onde em um loop for é interrompido quando a variável inteira contador se torna igual a 5.

 public class BreakTeste
{
    public static void main( String args[] )
    {
    int contador; //Variável de controle usada como referência
   
    for ( contador = 1; contador <= 10; contador++ )//Laço, será repetido 10 vezes
        {
        if ( contador == 5 ) //Se o contador chegar até 5
            break;        //Termina o loop quando a condição do if se tornar verdadeira
       
        System.out.printf( "%d ", contador);
        }//Termino da instrução for
   
    System.out.printf( "\nInterrompe o contador quando o contador = %d\n",contador );
    }//Fim do main
}//Fim da classe BreakTest

O comando continue editar

O comando continue serve para encerrar a execução de comandos e verificar o valor de CONDIÇÃO. Caso o valor seja "verdadeiro", a iteração continua. Caso contrário, ela se encerra. Exemplos de uso:

 for(int i=1;i<=10;i++){        //O loop é executado 10 vezes
     if(i%2==0)
          continue;
     System.out.println(i+" "); //Será impressa na tela os números ímpares entre 1 e 10
 }

for

Sintaxe editar

 for (int i=0; i<=10; i++) // i++ incrementando i
 {
  <bloco de comando>
 }

Exemplo de comando de repetição usando o FOR editar

A sintaxe deste comando é a seguinte:

for ([expressão 1]; [condição]; [expressão 2]){
   [comando]
}

Veja um exemplo:

/**
 * Exemplo de comando for
 */
public class ExemploDeFor {
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++){
			System.out.println("Indice " + i);
		}
	}
}

O Resultado obtido será:

Índice 0 
Índice 1 
Índice 2 
Índice 3 
Índice 4 
Índice 5 
Índice 6 
Índice 7 
Índice 8 
Índice 9

ForEach editar

ForEach funciona com Array ou toda class que implementa a interface Iterable:

public interface Iterable<T>{  
     public abstract Iterator<T> iterator();  
}

Exemplo de ForEach: editar

public class ForEach {
   
   public static void main(String [] args){
     String nomes[] = new String[5];

      nomes[0] = "joão";
      nomes[1] = "maria";
      nomes[2] = "josé";
      nomes[3] = "paulo";
      nomes[4] = "paula";

      for(String n : nomes){
         System.out.println(n);
      }

   }
}

Vetores

Definição de vetor editar

Um vetor é uma estrutura de dados formada por um conjunto de dados ou outros elementos de um mesmo tipo ou uma mesma estrutura. O vetor pode ter uma dimensão ou mais. Também chamado de matriz quando de duas dimensões, funciona de modo análogo às matrizes matemáticas. O acesso aos dados é feito através de "coordenadas" (índices).
A programação faz um grande uso de vetores. Cada item de um vetor é chamado de elemento. Cada um dos elementos possui uma posição dentro do vetor, à qual referenciamos através do índice do elemento. Cada um dos "domínios" (conjunto de posições, endereços de armazenamentos) do vetor, nos chamamos de dimensão. Já o tipo de dado (ou de elemento) corresponde ao "contradomínio" do vetor, ou seja, o conjunto de literais ou de outro tipo de elemento que o vetor pode armazenar.
Veja um vetor de uma dimensão e dez elementos:
 
Ele possui 10 elementos que são acessados (referenciados) pelos índices:
 [0], [1], [2], [3], [4], [5], [6], [7], [8], [9].
Os índices de cada elemento são escritos entre colchetes [ ].
Veja um vetor de duas dimensões e vinte e cinco elementos (5 x 5):
 
Ele possui 25 elementos que são acessados (referenciados) pelos índices:
 [0][0], [1][0], [2][0], [3][0], [4][0],
 [0][1], [1][1], [2][1], [3][1], [4][1],
 [0][2], [1][2], [2][2], [3][2], [4][2],
 [0][3], [1][3], [2][3], [3][3], [4][3],
 [0][4], [1][4], [2][4], [3][4], [4][4].
Cada elemento é representado por dois índices (um para cada dimensão), entre colchetes e adjacentes [ ][ ].
Veja um vetor de três dimensões e cento e vinte e cinco elementos (5 x 5 x 5):
 
Ele possui 125 elementos que são acessados (referenciados) pelos índices:
[0][0][0], [1][0][0], [2][0][0], [3][0][0], [4][0][0],
[0][1][0], [1][1][0], [2][1][0], [3][1][0], [4][1][0],
[0][2][0], [1][2][0], [2][2][0], [3][2][0], [4][2][0],
[0][3][0], [1][3][0], [2][3][0], [3][3][0], [4][3][0],
[0][4][0], [1][4][0], [2][4][0], [3][4][0], [4][4][0],
[0][0][1], [1][0][1], [2][0][1], [3][0][1], [4][0][1],
[0][1][1], [1][1][1], [2][1][1], [3][1][1], [4][1][1],
[0][2][1], [1][2][1], [2][2][1], [3][2][1], [4][2][1],
[0][3][1], [1][3][1], [2][3][1], [3][3][1], [4][3][1],
[0][4][1], [1][4][1], [2][4][1], [3][4][1], [4][4][1],
[0][0][2], [1][0][2], [2][0][2], [3][0][2], [4][0][2],
[0][1][2], [1][1][2], [2][1][2], [3][1][2], [4][1][2],
[0][2][2], [1][2][2], [2][2][2], [3][2][2], [4][2][2],
[0][3][2], [1][3][2], [2][3][2], [3][3][2], [4][3][2],
[0][4][2], [1][4][2], [2][4][2], [3][4][2], [4][4][2],
[0][0][3], [1][0][3], [2][0][3], [3][0][3], [4][0][3],
[0][1][3], [1][1][3], [2][1][3], [3][1][3], [4][1][3],
[0][2][3], [1][2][3], [2][2][3], [3][2][3], [4][2][3],
[0][3][3], [1][3][3], [2][3][3], [3][3][3], [4][3][3],
[0][4][3], [1][4][3], [2][4][3], [3][4][3], [4][4][3],
[0][0][4], [1][0][4], [2][0][4], [3][0][4], [4][0][4],
[0][1][4], [1][1][4], [2][1][4], [3][1][4], [4][1][4],
[0][2][4], [1][2][4], [2][2][4], [3][2][4], [4][2][4],
[0][3][4], [1][3][4], [2][3][4], [3][3][4], [4][3][4],
[0][4][4], [1][4][4], [2][4][4], [3][4][4], [4][4][4].

Declaração de um vetor editar

Para declarar um vetor, utiliza-se a seguinte sintaxe:

 tipo[] identificador;
ou
 tipo identificador[];
Onde:
tipo = tipo de dado ou de elemento;
identificador = nome do vetor.
Um vetor de duas dimensões é criado do seguinte modo:
 tipo[][] identificador;
ou
 tipo identificador[][];
Um vetor de três dimensões é criado do seguinte modo:
 tipo[][][] identificador;
ou
 tipo identificador[][][];
E assim, por diante - um vetor de quatro dimensões é criado do seguinte modo:
 tipo[][][][] identificador;
ou
 tipo identificador[][][][];

Dados em um vetor editar

Os elementos dos vetores podem ser atribuídos da seguinte forma (separados por vírgulas e entre chaves. Por exemplo, em um vetor unidimensional poderíamos indicar os dados de seus elementos assim:
{x0,x1,x2, ... ,xn}

onde cada um dos valores X é um valor do elemento de índice correspondente no vetor. A numeração dos índices começa a partir do 0 e pode ser somente número natural, ou seja, inteiro maior ou igual a zero.

Vetores podem ser declarados e iniciados conforme o seguinte exemplo - cada dimensão é delimitada por chaves e cada elemento é separado do outro através de vírgulas:
 int[] vetor={34, 27, 3, 2};
Outro modo de uso é declarando, iniciando com o tamanho (quantidade de elementos) do vetor e depois atribuindo os valores, como o equivalente a seguir:
 int[] vetor= new int[4];
 vetor={34, 27, 3, 2};
Ou então, atribuindo os elementos individualmente:
 int[] vetor= new int[4];
 vetor[0]=34;
 vetor[1]=27;
 vetor[2]=3;
 vetor[3]=2;
Observação: lembre-se que o ponto é utilizado para separar a parte inteira da parte fracionário de um número (notação inglesa) enquanto que a vírgula separa elementos.
Vetores de caracteres também são chamados de strings (cadeias de caracteres) e podem ser representados como um conjunto de caracteres cercado por aspas. Podemos declarar e atribuir tipos não básicos. No exemplo a seguir, frase é um vetor de objetos da classe String. Cada elemento de frase é também um vetor de caracteres. Por exemplo, "Bom dia" é o primeiro elemento do vetor frase e também, por si só, é um vetor de caracteres {'B','o','m',' ','d','i','a'}.
 String[] frase={"Bom dia","Boa tarde","Boa noite"};

Acessando os elementos do vetor editar

Para representar ou acessar um único elemento de um vetor, usa-se a sintaxe:
identificador[i1][i2][i3]...[in]
onde:
identificador = nome do vetor;
in = é a literal que representa o elemento de índice n.
Assim, no exemplo acima, frase[0] é igual a "Bom dia".

Observação: como a numeração dos índices começa em 0, frase poderá ter somente, no exemplo acima, os índices 0, 1 ou 2.

Cada dimensão do vetor é representada por um conjunto de colchetes. Assim, um vetor x de:
  • uma dimensão é acessado:
x[i1]
  • duas dimensões é acessado:
x[i1][i2]
  • três dimensões é acessado:
x[i1][i2][i3]
  • quatro dimensões é acessado:
x[i1][i2][i3][i4]
e assim por diante.

Comparando um vetor de duas dimensões com uma matriz algébrica editar

Por exemplo, podemos representar a seguinte matriz:

 

assim, em Java:
 int[][] B=new int[2][4];
 B={{8,0,9,2},
    {2,4,3,1}};
ou assim:
 int[][] B={{8,0,9,2},
            {2,4,3,1}};
ou assim:
 int[][] B=new int[2][4];
 B[0][0] = 8;
 B[0][1] = 0;
 B[0][2] = 9;
 B[0][3] = 2;
 B[1][0] = 2;
 B[1][1] = 4;
 B[1][2] = 3;
 B[1][3] = 1;

Declarando, iniciando e atribuindo valores a um vetor de duas ou mais dimensões editar

Para se atribuir valores às várias dimensões de vetor, separamos cada dimensão num bloco (por chaves) e seus elementos separados por vírgulas.
Exemplo de vetor de duas dimensões (2 elementos x 3 elementos):
 float[][] V={{1.5,2.7,3.5}, {1.2,3.0,4.5}};
O exemplo acima corresponde à seguinte matriz:

 

Então, no caso de duas dimensões, geralmente se formata o código em Java assim (para lembrar a representação "biordenada" da matriz):
 float[][] V={{1.5, 2.7, 3.5},
              {1.2, 3.0, 4.5}};
Cada dimensão está agrupada por chaves. Cada um dos elementos da dimensão são separados por vírgulas. Os números fracionários são representados com ponto ao invés de vírgula (entre a parte inteira e a fracionária).
Exemplo de um vetor de 3 dimensões (4 elementos x 3 elementos x 2 elementos), lembre-se que cada dimensão está agrupada entre chaves
 int[][] V2={
 {{1,65}, {2,47}, {33,5}},
 {{1,32}, {22,7}, {53,65}},
 {{1,5}, {12,7}, {23,5}},
 {{1,2}, {2,7}, {3,66}}};
Equivale à sobreposição (num espaço tridimensional) dessas duas matrizes (formando a terceira dimensão):
  e  

Arrays

A classe Arrays é uma classe utilitária que suporta operações em vetores. Seu nome qualificado é java.util.Arrays.

Exemplos de programas com vetores

Exemplo 2: Um Exemplo do Uso de Vetores editar

 public class ImprimeVetores{
    public static void main(String[] args){
        int[] vetor={3, 2, 5};
        System.out.println("O vetor possui os valores "+vetor[0]+", "+vetor[1]+" e "+vetor[2]);
    }
 }
  • LINHA 1: Uma nova classe chamada ImprimeVetores é criada
  • LINHA 2: O Método main é iniciado. Isso indica que a função ImprimeVetores é a principal.
  • LINHA 3: Um vetor de inteiros que representa (3, 2, 5) é criado e inicializado.
  • LINHA 4: É impressa uma string que forma o trecho "O vetor possui os seguintes valores ". Esta string é concatenada com o inteiro que é o primeiro número do vetor, que é concatenado com a string ", " e assim por diante. No final, o que será impresso será: "O vetor possui os valores 3, 2 e 5.". Logo em seguida, o programa se encerra.

Perceba que com o conhecimento visto até agora, os programas que estamos fazendo não são nem um pouco interativos e rodam sempre do mesmo jeito. Também não está sendo possível mostrar muitos detalhes da Programação Orientada à Objetos. Nos próximos capítulos veremos como fazer isso.

Exercícios sobre arrays

public class ImprimeVetores{

   public static void main(String[] args){
       int[] vetor={3, 2, 5};
       System.out.println("O vetor possui os valores "+vetor[0]+", "+vetor[1]+" e "+vetor[2]);
   }
}

Introdução às classes

O conhecimento sobre classes é um conhecimento global,sendo que toda linguagem orientada a objetos utiliza desse conceito para projetar seus objetos. Uma classe nada mais é do que um projeto de um objeto. Ao definirmos classes estamos modelando uma entidade que pode ser criada várias vezes com a mesma definição. Sendo que ao necessitarmos utilizar essa entidade temos que criar um objeto através do nosso modelo que é a classe. Fazendo uma analogia, uma receita de bolo seria a classe o resultado dessa receita, o bolo, seria o objeto.

Declaração de classes

Para declarar uma classe em java, utilizamos a palavra reservada class. Por exemplo:

Digamos que criamos a classe YouTube. Se quero declarar essa classe como de acesso geral utilizaria a seguinte sintaxe:

public class YouTube {
//IMPLEMENTAÇÃO DE MÉTODOS E ATRIBUTOS DA CLASSE
}
Se queres uma classe de acesso restrito:
private class YouTube {
}
Se queres uma classe de acesso restrito:
protected class YouTube {
}

Objetos

Elementos de software que representam entidades físicas ou abstratas, simples ou complexas, dentro de um sistema. Possuem identidade, responsabilidades específicas, estado e um conjunto de mensagens que estão aptos a responder.

  • Estáticos: Dependem de um agente externo ao objeto para solicitar que o objeto altere o seu estado.
  • Dinâmicos: O objeto é capaz de espontaneamente alterar o seu próprio estado.

Herança

Em java a herança é realizada de maneira simples ao utilizar a palavra chave extends:

Exemplo:

package academico;

public abstract class Pessoa {
    public String strNome;
    public String strTelefone;
// Métodos
    public void getStrNome(String Nome) {
        this.StrNome = Nome;
    }
    public String setStrNome() {
        return StrNome;
    }
}

public class Aluno extends Pessoa {
    // strNome e strTelefone, bem como seus metodos são herdados nesta calasse por meio da palavra "extends"

}


Quando uma classe é criada como sub-classe de outra classe, a palavra-chave super é usada para que a sub-classe possa acessar métodos public ou protected (mas não private) da superclasse. super também é usado para invocar o constructor da superclasse, durante o constructor da subclasse.

Sintaxe:

  super.<method_name>(<argumentos>);

ou

  super(<argumentos>); //Em contrutor

Outro exemplo:

public class SuperClass
{
   SuperClass(String title)
   {
      System.out.println( "Super: " + title );
   }

   public void printHello()
   {
      System.out.println( "Hello from SuperClass" );
     return;
   }
}

public class SubClass extends SuperClass
{
   SubClass(String title)// constructor
   {
       super(title);  // chama o constructor de Frame
   }
   public void printHello()
   {
      super.printHello();
      System.out.println( "Hello from SubClass" );
     return;
   }

   public static main( String[] args )
   {
      SubClass obj = new SubClass();
      obj.printHello();
   }
}

Modificadores

Modificadores editar

Modificadores de acesso editar

Os modificadores de acesso são palavras-chave que modificam a forma como podem ser acessadas as classes, métodos e/ou variáveis.

Modificador de acesso private editar

O modificador de acesso "private" quando aplicado a um atributo ou a um método indica que os mesmos só podem ser acessados de dentro da classe que os criou (encapsulamento). Uma classe que herde de uma superclasse com atributos declarados como "private" só poderá ter acesso a eles através dos métodos públicos da própria superclasse, caso contrário, não haverá acesso a estes atributos.

Exemplo

class Circulo
{    
    private float raio;
    Circulo()
       {
          super();
          setRaio( 3.0 );
       }
    void setRaio( float r )
       {
          raio = r
       }
}
class Pneu extends Circulo
{
    Pneu p = new Pneu();
    p.raio = 10.0; //Erro de compilação. O Atributo raio é privado da classe Circulo
    p.setRaio(10.0); //Correto, pois a classe Pneu está utilizando os métodos definidos na classe Circulo para fazer
                     //acesso ao atributo privado raio 
}

Modificador de acesso protected editar

A instrução protected indica que o método ou a variável assim declarada possa ser acessada somente dentro do pacote em que está contida através de uma subclasse.

Modificador de acesso public editar

A instrução public indica que a classe, método ou variável assim declarada possa ser acessada em qualquer lugar e a qualquer momento da execução do programa.

Friendly editar

Sem modificador de acesso, o membro da classe é considerado friendly. Não há uma palavra-chave para esse modificador.

Outros modificadores editar

Os modificadores a seguir podem ser usados em conjunto com os modificadores de acesso provendo, assim, outros comportamentos:

Modificador de acesso static editar

A palavra reservada static serve:
  • na declaração de uma variável dentro de uma classe, para se criar uma variável que será compartilhada por todas as instâncias de objetos de uma classe como um variável comum. Ou seja, a variável criada será a mesma em todas instâncias e quando seu conteúdo é modificado em uma das instâncias então ele será modificado em todas instâncias;
  • na declaração de um método que deve ser acessado diretamente na classe e não nas suas instâncias.

Modificador abstract editar

A instrução abstract serve para:
  • declarar métodos abstratos, ou seja, métodos que deverão ser desenvolvidos/implementados nas subclasses. Quando a classe que contiver métodos abstratos for herdada, os referidos métodos deverão ser implementados, caso contrário, a classe que extendeu deverá ser declarada como abstrata.
  • declarar classes abstratas que se desenvolvem numa(s) subclasse(s). Classes abstratas são aquelas que não estão totalmente implementadas/descritas. Uma classe abstrata não pode ser instanciada e é amplamente usada nas interfaces.
  • Uma classe é considerada abstrata se contiver pelo menos um método abstrato. Um método abstrato tem a seguinte característica: void getName( );
  • Caso o método tenha as chaves características {}, o mesmo não mais será considerado abstrato, embora não tenha código dentro das chaves.

Modificador final editar

A instrução final indica que a classe, método ou variável assim declarada têm uma única atribuição que se mantém constante, ou seja, não pode ser alterada no decorrer do processamento.
Além de não admitir a criação de classes filhas.
Este modificador declara o que chamamos, em programação, de constante.

Fluxos de entrada e saída

A entrada e saída de dados em Java é feita através de streams.

Uma stream é uma sequência ordenada de bytes ou caracteres de tamanho indefinido. Streams podem ser abertas e fechadas pelo programa; algumas vezes, estas operações são feitas de forma automática (normalmente em caso de erro).

Um programa que usa uma stream deve incluir a biblioteca java.io, ou seja, deve incluir logo no início:

  import java.io.*;

ou instruções equivalentes.

Assim como em C/C++, uma stream não é usada diretamente através do nome do arquivo; é preciso abri-la como um File para depois usar as operações em streams.

Por exemplo, o programa abaixo pega o arquivo "teste1.txt" e copia seu conteúdo (bit-a-bit) para o arquivo "teste2.txt":

  import java.io.*;

  public class exemplo_io {
      public static void main(String[] args) throws IOException {
          File inputFile = new File("teste1.txt");
          File outputFile = new File("teste2.txt");

          FileReader in = new FileReader(inputFile);
          FileWriter out = new FileWriter(outputFile);
          int c;

          while ((c = in.read()) != -1)
             out.write(c);

          in.close();
          out.close();
      }
  }

Explicações:

  File inputFile = new File("teste1.txt")
  File outputFile = new File("teste2.txt")

apenas associam os streams inputFile e outputFile aos nomes "teste1.txt" e "teste2.txt". Neste ponto, não foi dito que "teste1.txt" é entrada, nem que "teste2.txt" é saída (obvimente, os nomes inputFile e outputFile são apenas conveniência para o leitor do programa).

  FileReader in = new FileReader(inputFile);
  FileWriter out = new FileWriter(outputFile);

Neste ponto são criados os dois streams. in é o stream de entrada, e out é o stream de saída. Como, na declaração do main, previmos uma exceção no I/O, caso o arquivo de entrada "teste1.txt" não exista, será gerada uma mensagem de erro.

  int c;
  while ((c = in.read()) != -1)
    out.write(c);

c é um inteiro. read, enquanto houver elementos para serem lidos, retorna números naturais, e retorna -1 no final. write escreve este número. Este loop (extremamente ineficiente para arquivos grandes!) faz a cópia, caracter a caracter, do arquivo de entrada para o arquivo de saída.

  in.close();
  out.close();

fecha os streams.

Coleções

O Collections Framework também conhecido em línguas lusófonas como Coleções é uma arquitetura que provê implementações de estruturas de dados na API do Java. Suas classes, interfaces e enums estão localizadas no pacote java.util.

Collections

A classe Collections é uma classe utilitária que suporta operações em coleções. Assim como todas as outras coleções está localizada no pacote java.util.

Iterator

A interface java.util.Iterator tem a finalidade de prover capacidade de iteração às classes, principalmente as de coleções, que implementam java.util.Iterable.

ArrayList

A classe ArrayList é uma implementação da interface List que utiliza um vetor para armazenar elementos. Uma vez que vetores tem tamanho fixo em Java, a classe ArrayList se encarrega de criar um novo vetor (internamente) com um tamanho maior e copiar seus elementos correntes para esse novo vetor sempre que for necessário.

O vetor interno da classe ArrayList é recriado quando há remoções de elemento, adições de elemento no fim da lista além da capacidade dimensionada e adições de elementos que não no final da lista.

Como a operação de recriação do vetor é custosa, busque dimensionar previamente o tamanho da lista, para tal, utilize o construtor sobrecarregado ArrayList(int) enviando como argumento a capacidade inicial da lista. A capacidade inicial padrão de um objeto ArrayList é de 10 elementos.

Performance editar

Métodos não constantes na interface List editar

package livro_java.colecoes.listas;

import java.util.ArrayList;

public class UtilizandoArrayList {

    public static void main(String[] args) {

        ArrayList<NavegadorWeb> listaOriginal = new ArrayList<>(2);
        ArrayList<NavegadorWeb> listaClone;
        
        listaOriginal.ensureCapacity(15);
        
        listaOriginal.add(new NavegadorWeb("Chrome", "Google"));
        listaOriginal.add(new NavegadorWeb("Firefox", "Mozilla"));
        listaOriginal.add(new NavegadorWeb("Internet Explorer", "Microsoft"));

        listaOriginal.trimToSize();

        listaClone = (ArrayList<NavegadorWeb>) listaOriginal.clone();

        System.out.printf("%-20s %s%n", "Lista Original", listaOriginal);
        System.out.printf("%-20s %s%n", "Lista Clonada", listaClone);

        listaClone.get(2).setNome("Edge");
        listaClone.remove(1);

        System.out.println("\nApós alteração\n");
        System.out.printf("%-20s %s%n", "Lista Original", listaOriginal);
        System.out.printf("%-20s %s%n", "Lista Clonada", listaClone);

    }
}

class NavegadorWeb {
    private String nome;
    private String empresa;

    NavegadorWeb(String nome, String empresa) {
        this.nome = nome;
        this.empresa = empresa;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public String toString() {
        return empresa + " " + nome;
    }
}

Saída

Lista Original       [Google Chrome, Mozilla Firefox, Microsoft Internet Explorer]
Lista Clonada        [Google Chrome, Mozilla Firefox, Microsoft Internet Explorer]

Após alteração

Lista Original       [Google Chrome, Mozilla Firefox, Microsoft Edge]
Lista Clonada        [Google Chrome, Microsoft Edge]

Foi utilizado o construtor sobrecarregado ArrayList<>(int) para definir a capacidade inicial do vetor interno. Não confunda a capacidade inicial do vetor com o tamanho da Lista. O tamanho é devolvido pelo método size() e corresponde à quantidade de elementos armazenados já a capacidade é o tamanho do vetor interno o qual não temos acesso.

O método ensureCapacity(int) recriou o vetor interno com o capacidade para 15 elementos.

O método trimToSize(int) recriou novamente o vetor interno, porém agora com a capacidade igual ao tamanho da lista, no caso 3.

O método clone(), sobrescrito de Object e indicado pela implementação da interface Clonable, atribuiu uma instância de ArrayList à variável listaClone com os mesmos elementos, que são as referências às 3 instâncias do objeto NavegadorWeb que incluímos na variável listaOriginal. Como o método clone() devolve um tipo Object, foi necessário o uso do cast com o tipo (ArrayList<Navegador>). Conforme evidenciado na chamada do método setNome("Edge") o método clone() apenas copia a lista e não cada um de seus elementos e com a chamada ao método remove(1) percebemos que as instâncias de ArrayList nas variáveis listaOriginal e listaClone são diferentes e portanto desvinculadas.

Como você pode ter concluído, o uso dos métodos ensureCapacity(int) e trimToSize(int) não é recomendável pois eles recriam o vetor interno do objeto ArrayList situação em que a performance é prejudicada.

Exercício editar

  1. Depure o código acima e observe em que chamadas de métodos o atributo elementData é alterado.
  2. Os métodos add() e remove() alteram a capacidade da instância de ArrayList das variáveis listaOriginal e listaClone?

A classe Thread

Resumidamente, uma Thread em Java é composta de três partes:

  1. CPU ( processamento compartilhado para executar rotinas )
  2. Código ( linhas de código de uma rotina que serão executadas )
  3. Dados ( área de dados que fazem parte da execução da rotina )

Ou seja, o objeto Thread do Java proveniente da classe java.lang.Thread, representa uma instância da CPU da máquina virtual Java, e que tem associada um trecho de código que será executado, e uma área de memória.

Podemos criar uma Thread em Java de duas maneiras:

  1. Estendendo o comportamento da classe Thread
  2. Implementando a interface Runnable

Criando uma Thread a partir da classe java.lang.Thread editar

O código abaixo mostra como criar uma classe que [funciona][1] como uma Thread:

// MinhaThread.java
public class MinhaThread extends java.lang.Thread {

    // área de dados da Thread
    private int contador; 
    private int limite;
    
    // inicializador da MinhaThread 
    public MinhaThread( int limite ) {
        this.limite = limite; 
        this.contador = 0;
    }

    // área de código da Thread
    public void run() {
        while (contador <= limite) {
            System.out.println( super.getName() + "\t" + contador );
            contador ++;
            // trecho de código para demonstração somente
            try {
                Thread.sleep( 1000 ); // coloca a "thread" para "dormir" 1 segundo
            } catch (InterruptedException e) {
                e.printStackTrace( System.err );
            }
        }
    }
}

O código abaixo mostra como usar a classe MinhaThread:

// TesteMinhaThread.java
public class TesteMinhaThread {
    
    public static void main(String[] args) {
        MinhaThread mt1 = new MinhaThread( 200 );
        mt1.setName("MinhaThread1");
        MinhaThread mt2 = new MinhaThread( 300 );
        mt2.setName("MinhaThread2");
        MinhaThread mt3 = new MinhaThread( 200 );
        mt3.setName("MinhaThread3");
        MinhaThread mt4 = new MinhaThread( 400 );
        mt4.setName("MinhaThread4");
        mt2.start();
        mt1.start();
        mt3.start();
        mt4.start();
    }
}

Executando o classe TesteMinhaThread, veremos que as Threads incrementam o contador separadamente, baseado no objeto MinhaThead.

Criando uma Thread a partir da interface java.lang.Runnable editar

O código abaixo mostra como criar uma classe que funciona como uma Thread:


// MeuRunnable.java
public class MeuRunnable implements java.lang.Runnable {

    // área de dados da Thread
    private int contador; 
    private int limite;
    
    // inicializador da MinhaThread 
    public MeuRunnable ( int limite ) {
        this.limite = limite; 
        this.contador = 0;
    }

    // área de código da Thread
    public void run() {
        while (contador <= limite) {
            System.out.println( Thread.currentThread().getName() + "\t" + contador );
            contador ++;
            // trecho de código para demonstração somente
            try {
                Thread.sleep( 1000 ); // coloca a "thread" para "dormir" 1 segundo
            } catch (InterruptedException e) {
                e.printStackTrace( System.err );
            }
        }
    }
}

O código abaixo mostra como usar a classe MeuRunnable:

// TesteMeuRunnable.java
public class TesteMeuRunnable {
    
    public static void main(String[] args) {
        MeuRunnable mr1 = new MeuRunnable ( 300 );
        MeuRunnable mr2 = new MeuRunnable ( 200 );
        MeuRunnable mr3 = new MeuRunnable ( 400 );
        MeuRunnable mr4 = new MeuRunnable ( 200 );
        Thread t1 = new Thread( mr1 );
        t1.setName("MeuRunnable1");
        Thread t2 = new Thread( mr2 );
        t2.setName("MeuRunnable2");
        Thread t3 = new Thread( mr3 );
        t3.setName("MeuRunnable3");
        Thread t4 = new Thread( mr4 );
        t4.setName("MeuRunnable4");
        t2.start();
        t1.start();
        t3.start();
        t4.start();
    }
}

Executando o classe TesteMeuRunnable, veremos que as Threads incrementam o contador separadamente, baseado no objeto MeuRunnable.

Considerações de Design editar

  • Usar a implementação do Runnable, dá maior flexibilidade de Design, pois permite que a classe que implementou a interface java.lang.Runnable estenda o comportamento de outra classe.
  • Estender diretamente a classe Thread, facilita o acesso aos métodos da classe java.lang.Thread, mas dificulta a modelagem da POO pois impede que a sub-classe de Thread estenda outra classe.

Desafio editar

Criar uma pequena aplicação gráfica usando a Java SWING API de simulador simples para um prédio que tenha 3 elevadores e que funcionam independentemente.

Ligações externas editar

GUI

As principais interfaces gráficas para Java são AWT e Swing.

AWT editar

 
Exemplo de AWT

Abstract Window Toolkit foi a interface gráfica original da linguagem.

Swing editar

 Ver módulo principal: Java/Swing
 
Examplo de Swing

A interface Swing foi desenvolvida depois da AWT, e é considerada mais fácil de ser usada e com mais recursos.

Swing

Swing é uma API Java para interfaces gráficas. Ela é compatível com a API AWT, mas trabalha de uma maneira totalmente diferente. A API Swing procura renderizar\desenhar por contra própria todos os componentes, ao invés de delegar essa tarefa ao sistema operacional, como a maioria das outras APIs de interface gráfica trabalham.

Por ser uma API de mais alto nível, ou seja, mais abstração, menor aproximação das APIs do sistema operacional, ela tem bem menos performace que outras APIs gráficas e consome mais memória RAM em geral. Porém, ela é bem mais completa, e os programas que usam Swing têm uma aparência muito parecida, independente do Sistema Operacional utilizado.

Este capítulo segue a estrutura do livro Programação em GUI

Índice editar

Ver também editar

 
Wikipedia
A Wikipédia tem mais sobre este assunto:
Java Swing

Autores

Os usuários citados abaixo contribuiram para o desenvolvimento deste trabalho. Estes dados foram obtidos em 16/12/2013.

Abacaxi, Albmont, Alexandref93, Alexandreqo, Alguém, Daniel Souza, Dante Cardoso Pinto de Almeida, David Stress, Devarde, Edufsousa, Ezarate, Felipe Gustavo Firmo, Fesaopilger, Guiwp, Helder.wiki, Helder.wiki.bot, Hojerio, JackPotte, Jonas AGX, Jorge Morais, Julianocanuto, LipeFontoura, Luís Felipe Braga, Lukas²³, Marco Antonio Bidóia, Marcos Antônio Nunes de Moura, Master, Maxtremus, MGFE Júnior, Mike.lifeguard, Nunesnd, PatiBot, PatríciaR, Profvalente, Raylton P. Sousa, Ruy Pugliesi, SallesNeto BR, Scorpion, Seduardo, Sfragata, Thiagoharry, Voz da Verdade, Wbrito, Webcentro, Wutsje.

Palavra-chave

Em programação, palavras-chave, ou palavras reservadas, são as palavras que não podem ser usadas como identificadores, ou seja, não podem ser usadas como nome de variáveis, nome de classes, etc. Estas palavras são assim definidas ou porque já têm uso na sintaxe da linguagem ou porque serão usadas em alguns momento, seja para manter compatibilidade com versões anteriores ou mesmo com outras linguagens. No caso do Java temos as seguintes palavras-chave:
abstract continue for new switch
assert(3) default goto(1) package synchronized
boolean do if private this
break double implements protected throw
byte else import public throws
case enum(4) instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp(2) volatile
const(1) float native super while
null

(1) sem uso na linguagem
(2) somente a partir da versão 1.2
(3) somente a partir da versão 1.4
(4) somente a partir da versão 5.0


Ferramentas

Ferramentas da Linguagem Java editar

As ferramentas são os programas fornecidos no JSDK:

  • appletviewer
  • apt
  • extcheck
  • htmlconverter
  • keytool
  • jar
  • jarsigner
  • java
  • javac
  • javadoc
  • javah
  • javap
  • javaw
  • javaws
  • jconsole
  • jdb
  • jinfo
  • jmap
  • jps
  • jsadebugd
  • jstack
  • jstat
  • jstatd
  • kinit
  • klist
  • ktab
  • idlj
  • native2ascii
  • orbd
  • pack200
  • policytool
  • rmic
  • rmiregistry
  • rmid
  • serialver
  • servertool
  • tnameserv
  • unpack200

RMI

Introdução editar

A tecnologia Java RMI (Remote Method Invocation) consiste em uma biblioteca capaz de permitir que um programa rodando em uma dada máquina efetue chamadas à objetos instanciados em outra máquina. Apesar de ser desenvolvida focando principalmente a chamada de procedimentos à objetos localizados em máquinas distintas ela também pode ser utilizada para efetuar a comunicação entre dois processos rodando na mesma máquina (desde que ambos utilizem a JVM), muito embora tecnologias como XPCOM e outras possam disponibilizar performance e integração melhores.

Tenologias semelhantes editar

Existem duas outras tecnologias que se assemelham muito com a RMI: CORBA e .NET Remoting (que no .NET 3.0 foi incorporada pela WCF). A tecnologia .NET Remoting é pode ser vista como a resposta Microsoft à tecnologia RMI, e possui quase as mesmas características. Já a tecnologia CORBA é divulgada à mais tempo e possui a vantagem de possuir bibliotecas em diversas linguagens, assim um objeto CORBA pode ser utilizado em vários programas escritos em linguagens diferentes (a tecnologia RMI foi feita exclusivamente para a plataforma Java).

Um exemplo rápido editar

Para demonstrar a facilidade da linguagem, vou criar um exemplo bem simples que irá utilizar a tecnologia RMI. Um pequeno aplicativo para postar mensagens em um fórum e listar as mesmas.

Primeiro devemos criar uma interface que será utilizada para exibir aos usuários dos serviço as operações.

package rmiknolexample;

import java.rmi.RemoteException;
import java.rmi.Remote;

/**
 *
 * @author Andre
 */
public interface IForum 
        extends Remote {
    public void postMessage(String author, String aMessage) throws RemoteException;
    public String[] readPosts() throws RemoteException;
    public String[] readPosts(int beginAt) throws RemoteException;
}

Depois devemos criar uma classe que irá implementar a interface e disponibilizar a funcionalidade.

package rmiknolexample;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;

/**
 *
 * @author Andre
 */
public class ForumImpl 
        extends UnicastRemoteObject 
        implements IForum {
    
    private Vector posts;
    
    // O construtor padrão deve gera a exceção RemoteException
    public ForumImpl() throws RemoteException {
        posts = new Vector();
    }

    public void postMessage(String author, String aMessage) throws RemoteException {
        posts.add(author + " disse uma vez: " + aMessage);
    }

    public String[] readPosts() throws RemoteException {
        String[] result = new String[posts.size()];
        posts.toArray(result);
        return result;
    }

    public String[] readPosts(int beginAt) throws RemoteException {
        String[] results = readPosts();
        String[] copy = new String[results.length - beginAt];
        System.arraycopy(results, beginAt, copy, 0, copy.length);
        return copy;
    }

Feito isso vamos implementar a classe que irá disponibilizar o serviço ao usuário.

package rmiknolexample;

import java.rmi.Naming;
import java.rmi.RemoteException;

/**
 *
 * @author Andre
 */
public class ForumService {
    public static void main(String[] args) {
        try {
            ForumImpl forumObj = new ForumImpl();
            Naming.rebind("forumService", forumObj);
            System.err.println("Rodando");
        } catch(RemoteException e) {
            System.err.println("Ocorreu um erro relativo ao RMI: " + e.getMessage());
            e.printStackTrace();
            System.exit(0);
        } catch(Exception e) {
            System.err.println("Ocorreu um erro desconhecido: " + e.getMessage());
            e.printStackTrace();
            System.exit(0);
        }
    }
}

Na classe acima observe a linha:

Naming.rebind("forumService", forumObj);

Ela é responsável por associar um nome ao seu objeto. É através deste nome que os computadores e processos remotos irão encontrar e utilizar o seu objeto. Este nome é único para um dado host, ou seja, mesmo se duas aplicações criarem objetos distintos (até mesmo de classes distintas) o mesmo nome não poderá ser utilizado.

Por último vamos implementar a classe que irá utilizar o serviço disponibilizado.

package rmiknolexample;

import java.rmi.Naming;
import java.rmi.RemoteException;

/**
 *
 * @author Andre
 */
public class ForumClient {
    public static void main(String[] args) {
        try {
            IForum forumObj = (IForum)Naming.lookup("rmi://localhost/forumService");
            forumObj.postMessage("autor", "Java RMI é muito legal");
            forumObj.postMessage("autor", "Nunca poste no fórum sem buscar");
            String[] posts = forumObj.readPosts();
            
            int x = 1;
            for(String s: posts)
                System.err.println(x++ + ": "+ s);
            
            int offset = 1;
            posts = forumObj.readPosts(offset);
            for(String s: posts)
                System.err.println((x++ + offset) + ": "+ s);                        
            
        } catch(RemoteException e) {
            System.err.println("Ocorreu um erro relativo ao RMI: " + e.getMessage());
            e.printStackTrace();
            System.exit(0);
        } catch(Exception e) {
            System.err.println("Ocorreu um erro desconhecido: " + e.getMessage());
            e.printStackTrace();
            System.exit(0);
        }        
    }
}

A linha:

IForum forumObj = (IForum)Naming.lookup("rmi://localhost/forumService");

Efetua uma consulta no host informado (neste caso o localhost) e solicita o objeto associado ao nome: forumService.

O resto do código fala por si só, e graças ao RMI as chamadas são idênticas á chamadas locais. Melhorando um pouco o design da aplicação é possível criar um objeto local ou então um remoto dependendo da ocasião.

Para facilitar o teste, a classe abaixo foi criada apenas para permitir rodar o serviço através da linha de comando: "java -jar arquivoJar.jar"

package rmiknolexample;

/**
 *
 * @author Andre
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        if (args[0].equals("server"))
            ForumService.main(args);
        else if (args[0].equals("client"))
            ForumClient.main(args);
        else
            System.err.println("Usage: ");
    }
}

pronto! Para executar basta compilar as classes, iniciar o aplicativo rmiregistry que é o responsável por encontrar e disparar as chamadas aos objetos corretos e iniciar o servidor em um terminal ou prompt.

Após isso feito abra outro terminal ou prompt e inicie a aplicação cliente.

Observação importante: neste caso o teste é apenas local mas quando utiliza-se um ambiente com diversas máquinas é muito importante iniciar a aplicação servidor com a opção: -Djava.rmi.server.hostname=<nome_ou_ip_do_host>. Caso não seja feito o objeto pode ser exportado com o host errado e a aplicação cliente pode tentar disparar o procedimento em um endereço diferente do solicitado.

Existem diversas outras características da tecnologia RMI que não foram abordadas, como por exemplo a capacidade de baixar o código de uma determinada classe de modo transparente. Assim mesmo que o contexto local não reconheça uma classe esta será transferida do servidor e poderá ser utilizada pela aplicação.

Fontes e referências editar