Introdução à Programação em Java, Parte 1: Fundamentos da linguagem Java

Programação orientada a objetos na plataforma Java

Este tutorial em duas partes apresenta a estrutura, sintaxe e paradigma de programação da ™ linguagem e plataforma Java. Você aprenderá a sintaxe Java que, mais provavelmente, encontrará na profissão e os idiomas da programação em Java que poderá usar para desenvolver aplicativos Java robustos e de fácil manutenção. Na parte 1, J. Steven Perry guia você pelos fundamentos da programação orientada a objetos na plataforma Java, inclusive a sintaxe Java fundamental e o seu uso. Você verá uma introdução sobre como criar objetos Java, incluir comportamento neles e, para concluir, verá uma introdução ao Java Collections Framework, abordando vários assuntos relacionados.

J Steven Perry, Principal Consultant, Makoto Consulting Group, Inc.

Photo of J Steven PerryJ. Steven Perry é um consultor de desenvolvimento de software independente e vem desenvolvendo software profissionalmente desde 1991. Steve tem paixão por desenvolvimento de software e gosta de escrever sobre desenvolvimento de software e de orientar outros desenvolvedores. Ele é autor de Java Management Extensions (O'Reilly) e Log4j (O'Reilly), e Joda-Time (que escreveu para o IBM developerWorks). Em seu tempo livre, ele sai com seus três filhos, anda de bicicleta e ensina ioga. Steve é o proprietário e o principal consultor do Makoto Consulting Group, localizado em Little Rock, Arkansas.



17/Mai/2011

Antes de iniciar

Saiba o que esperar deste tutorial e como aproveitá-lo ao máximo.

Sobre este tutorial

O tutorial em duas partes "Introdução à programação em Java" se destina a ensinar os desenvolvedores de software iniciantes em Java a usar a tecnologia de programação orientada a objetos (OOP) e o desenvolvimento de aplicativos concreto por meio da plataforma e linguagem Java.

Esta primeira parte é uma introdução passo a passo à OOP usando a linguagem Java. O tutorial começa com uma visão geral da plataforma e linguagem Java e é seguido por instruções para configurar um ambiente de desenvolvimento formado por um Java Development e pelo IDE Eclipse. Depois de ser apresentado aos componentes do ambiente de desenvolvimento, você começará a aprender de forma prática a sintaxe Java.

A Parte 2 trata de recursos mais avançados da linguagem, como expressões regulares, genéricos, E/S e serialização. Os exemplos de programação da Parte 2 se baseiam no objeto Person que você começou a desenvolver na Parte 1.

Objetivos

Depois de terminar a Parte 1, você estará familiarizado com a sintaxe básica da linguagem Java e saberá escrever programa Java simples. Você deve continuar com a "Introdução à programação em Java, Parte 2: Construções para aplicações concretas " para se basear nesse fundamento.

Pré-requisitos

Esse tutorial é para desenvolvedores de software que ainda não têm experiência com o código ou a plataforma Java. O tutorial inclui uma visão geral dos conceitos de OOP.

Requisitos do sistema

Para fazer os exercícios desse tutorial, instale e configure um ambiente de desenvolvimento formado por:

  • JDK 6 da Sun/Oracle.
  • IDE Eclipse para desenvolvedores em Java.

As instruções de download e instalação de ambos estão incluídas no tutorial.

A configuração do sistema recomendada é:

  • Um sistema que suporta Java SE 6 com pelo menos1 GB de memória principal. O Java 6 é suportado em Linux®, Windows® e Solaris®.
  • Pelo menos 20 MB de espaço em disco para instalar os componentes de software e exemplos.

Visão geral da plataforma Java

A tecnologia Java é usada para desenvolver aplicativos para uma ampla variedade de ambientes, de dispositivos para o consumidor a sistemas corporativos heterogêneos. Nesta seção, obtenha uma visão geral da plataforma Java e dos seus componentes. Consulte a seção Recursos para saber mais sobre os componentes da plataforma Java abordados nesta seção.

A linguagem Java

Conheça as APIs Java

A maioria dos desenvolvedores em Java consulta constantemente a documentação oficial da API Java on-line — também conhecida como Javadoc (consulte Recursos ). Por padrão, você vê três quadros no Javadoc. O quadro superior esquerdo mostra todos os pacotes da API; abaixo, estão as classes de cada pacote. O quadro principal (à direita) mostra detalhes da classe ou do pacote selecionado no momento. Por exemplo: se você seleciona o pacote java.util no quadro superior esquerdo e, em seguida, seleciona a classe ArrayList listada abaixo dele, no quadro da direita você verá detalhes sobre ArrayList, inclusive uma descrição do que ela faz, como usá-la e seus métodos.

Como acontece em qualquer linguagem de programação, a linguagem Java tem a sua própria estrutura, regras de sintaxe e paradigma de programação. O paradigma de programação da linguagem Java se baseia no conceito de programação orientada a objetos (OOP), que os recursos da linguagem suportam.

A linguagem Java é uma derivação da linguagem C; portanto, as suas regras de sintaxe são muito semelhantes às regras dessa linguagem — por exemplo: os blocos de códigos são modulados em métodos e delimitados por chaves ({ e }) e as variáveis são declaradas antes de serem usadas.

Estruturalmente, a linguagem Java começa com pacotes . O pacote é o mecanismo de namespace da linguagem Java. Dentro do pacote há classes e dentro das classes há métodos, variáveis, constantes, etc. Neste tutorial, você aprenderá sobre as partes da linguagem Java.

O compilador Java

Quando você programa para a plataforma Java, escreve o código de origem em arquivos .java e em seguida os compila. O compilador verifica o seu código com relação às regras de sintaxe da linguagem e, em seguida, grava bytecodes em arquivos .class. Os bytecodes são instruções padrão que devem ser executadas em uma Java virtual machine (JVM). Ao incluir esse nível de abstração, o compilador Java é diferente dos compiladores de outras linguagens, que gravam instruções adequadas para o conjunto de chips da CPU no qual o programa será executado.

A JVM

No tempo de execução, a JVM lê e interpreta os arquivos .class e executa as instruções do programa na plataforma de hardware nativa para a qual a JVM foi escrita. A JVM interpreta os bytecodes da mesma forma que a CPU interpretaria as instruções da linguagem do conjunto. A diferença é que a JVM é um software escrito especificamente para uma plataforma. A JVM é o ponto central do princípio da linguagem Java: "escreva uma vez, execute em qualquer lugar". O código pode executar em qualquer conjunto de chips para o qual uma implementação adequada de JVM estiver disponível. Há JVMs disponíveis para as principais plataformas, como Linux e Windows, e subconjuntos da linguagem Java foram implementados em JVMs de chips para celulares e praticantes de hobby.

O coletor de lixo

Em vez de obrigá-lo a acompanhar a alocação de memória (ou usar uma biblioteca de terceiros para fazer isso), a plataforma Java fornece gerenciamento de memória de fábrica. Quando o seu aplicativo Java cria uma instância de objeto no tempo de execução, a JVM aloca automaticamente o espaço na memória para esse objeto no heap, que é um conjunto de memória separado para que o seu programa o use. O coletor de lixo executa em segundo plano, verificando quais são os objetos que não são mais necessários para o aplicativo e tomando de volta a memória reservada a eles. Essa abordagem à manipulação da memória é chamada gerenciamento implícito da memória porque não requer que você escreva código para manipular a memória. A coleta de lixo é um dos recursos essenciais para o desempenho da plataforma Java.

O Java Development Kit

Ao fazer o download de um Java Development Kit (JDK), você obtém — além do compilador e de outras ferramentas — uma biblioteca de classes completa de utilitários pré-construídos que ajudam a realizar qualquer tarefa comum no desenvolvimento de aplicativos. A melhor forma de ter uma ideia do escopo dos pacotes e bibliotecas do JDK é dar uma olhada na documentação da API JDK (consulte Recursos ).

O Java Runtime Environment

O Java Runtime Environment (JRE; também conhecido como Java Runtime) inclui a JVM, bibliotecas de código e os componentes necessários para executar programas escritos na linguagem Java. Está disponível para várias plataformas. É permitido redistribuir gratuitamente o JRE com os seus aplicativos, de acordo com os termos da licença do JRE, para oferecer aos usuários do aplicativo uma plataforma para executar o seu software. O JRE está incluído no JDK.


Configurando o ambiente de desenvolvimento Java

Nesta seção, você obterá instruções para fazer o download e instalar o JDK 6 e o release atual do IDE Eclipse e para configurar o seu ambiente de desenvolvimento Eclipse.

Se você já instalou o JDK e o IDE Eclipse, pode ir para a seção Iniciação ao Eclipse ou para a seção depois dela, Conceitos de programação orientada a objetos.

O seu ambiente de desenvolvimento

O JDK inclui um conjunto de ferramentas de linha de comando para compilar e executar código Java, inclusive uma cópia completa do JRE. Embora você certamente possa usar algumas dessas ferramentas para desenvolver os seus aplicativos, a maioria dos desenvolvedores aprecia a funcionalidade adicional, o gerenciamento de tarefas e a interface visual de um IDE.

O Eclipse é um IDE de software livre para o desenvolvimento Java que é bastante difundido. Ele realiza tarefas básicas, como compilação de código e configuração de um ambiente de depuração, para que você possa se concentrar no processo de escrever e testar o código. Além disso, é possível usar o Eclipse para organizar arquivos de código de origem em projetos, compilar e testar esses projetos e armazenar arquivos de projeto em qualquer quantidade de repositórios de origem. Para usar Eclipse para desenvolvimento Java, é necessário ter o JDK instalado.

Instale o JDK 6

Siga estas etapas para fazer o download do JDK e instalá-lo:

  1. Navegue para Java SE Downloads e clique na caixa Java Platform (JDK) para exibir a página de download referente à versão mais recente do JDK (no momento em que este artigo foi escrito, JDK 6, atualização 21).
  2. Clique no botão Download .
  3. Selecione a plataforma de sistema operacional de que você precisa.
  4. O programa pedirá o nome de usuário e a senha da conta. Insira-os se você tiver uma conta, inscreva-se se não tiver ou clique em Continue para ignorar essa etapa e passar ao download.
  5. Salve o arquivo na unidade de disco rígido quando isso for solicitado.
  6. Quando o download terminar, execute o programa de instalação. (O arquivo que você acabou de transferir por download é um arquivo zip autoextrator e também o programa de instalação.) Instale o JDK na unidade de disco rígido, em um local fácil de lembrar (como C:\home\jdk1.6.0_20 no Windows ou ~/jdk1.6.0_20 no Linux). É recomendável indicar o número da atualização no nome do diretório de instalação que você escolher.

Agora você tem um ambiente Java na sua máquina. Em seguida, você instalará o IDE Eclipse.

Instale o Eclipse

Para fazer o download do Eclipse e instalá-lo, siga estas etapas:

  1. Navegue para Eclipse Galileo Sr2 Packages.
  2. Clique em Eclipse IDE for Java Developers.
  3. Em Download Links, no lado direito, selecione a plataforma.
  4. Selecione o espelho a partir do qual você quer fazer o download e, em seguida, salve o arquivo na unidade de disco rígido.
  5. Extraia o conteúdo do arquivo zip em um local da unidade de disco rígido que seja fácil de lembrar (como C:\home\eclipse no Windows ou ~/eclipse no Linux).

Configure o Eclipse

O IDE Eclipse faz parte do JDK como uma abstração útil mas, mesmo assim, precisa acessar o JDK e suas várias ferramentas. Antes de poder usar o Eclipse para escrever código Java, é necessário informar onde ele está localizado.

Para configurar o ambiente de desenvolvimento Eclipse:

  1. Ative o Eclipse clicando duas vezes em eclipse.exe (ou no executável equivalente para a sua plataforma).
  2. O Workspace Launcher aparecerá, permitindo que você selecione uma pasta raiz para os seus projetos Eclipse. Escolha uma pasta fácil de lembrar, como C:\home\workspace no Windows ou ~/workspace no Linux.
  3. Ignore a tela Welcome to Eclipse.
  4. Clique em Window > Preferences > Java > Installed JREs. A Figura 1 mostra a tela de configuração do JRE:
    Figura 1. Configurando o JDK usado pelo Eclipse
    Configurando o JDK usado pelo Eclipse
  5. O Eclipse apontará para um JRE instalado. É necessário se certificar de usar o JRE que você transferiu por download com o JDK 6. Se o Eclipse não detectou automaticamente o JDK que você instalou, clique em Add... . No próximo diálogo, clique em Standard VM e, em seguida, clique em Next..
  6. Especifique o diretório inicial do JDK (como C:\home\jdk1.6.0_20 no Windows) e, em seguida, clique em Finish.
  7. Confirme que o JDK que você quer usar está selecionado e clique em OK.

Agora o Eclipse está configurado e pronto para que você crie projetos, compile e execute código Java. Ao ler a próxima seção, você ficará familiarizado com o Eclipse.


Iniciação ao Eclipse

O Eclipse não é só um IDE — é um ecossistema de desenvolvimento. Esta seção é uma breve introdução prática ao uso do Eclipse para desenvolvimento em Java. Consulte a seção Recursos se quiser saber mais sobre o Eclipse.

O ambiente de desenvolvimento Eclipse

O ambiente de desenvolvimento Eclipse tem quatro componentes principais:

  • Área de trabalho
  • Projetos
  • Perspectivas
  • Visualizações

A principal unidade de organização do Eclipse é a área de trabalho. A área de trabalho contém todos os projetos. Uma perspectiva é um ponto de vista em relação a cada projeto (daí o nome); dentro de cada perspectiva, há uma ou mais visualizações.

A perspectiva Java

A Figura 2 mostra a perspectiva Java, que é a perspectiva padrão do Eclipse. Você deve ver essa perspectiva ao inicializar o Eclipse.

Figura 2. perspectiva Java do Eclipse
perspectiva Java do Eclipse

A perspectiva Java contém as ferramentas necessárias para começar a escrever aplicativos Java. Cada guia mostrada na Figura 2 é uma visualização da Java perspective. Package Explorer e Outline são visualizações muito úteis.

O ambiente Eclipse é altamente configurável. Cada visualização é acoplável, para permitir que você se movimente na perspectiva Java e a coloque onde quiser. Entretanto, por enquanto, limite-se à perspectiva e configuração de exibições padrão.

Crie um projeto

Siga estas etapas para criar um novo projeto Java:

  1. Clique em File > New > Java Project ... e você verá uma caixa de diálogo aberta, semelhante à caixa mostrada na Figura 3:
    Figura 3. Assistente New Java Project
    Assistente New Java Project
  2. Insira Intro como nome do projeto e clique em Finish.
  3. Se quiser modificar os valores padrão do projeto, clique em Next.. (É recomendável fazer isso somente se você tiver experiência com o IDE Eclipse.)
  4. Clique em Finish para aceitar a configuração do projeto e criar o projeto.

Agora você criou um novo projeto Java Eclipse e uma pasta de origem. O ambiente de desenvolvimento está pronto para o trabalho. Entretanto, o entendimento do paradigma de OOP — abordado nas duas seções seguintes deste tutorial — é essencial. Se você está familiarizado com os conceitos e princípios de OOP, pode ir para Iniciação à linguagem Java.


Conceitos de programação orientada a objetos

A linguagem Java é, em grande parte, orientada a objetos. Se você nunca usou uma linguagem orientada a objetos, seus conceitos podem parecer estranhos à primeira vista. Esta seção é uma breve introdução aos conceitos de linguagem OOP, usando a programação estruturada como ponto de contraste.

O que é um objeto?

As linguagens de programação estruturada, como C e COBOL, seguem um paradigma de programação muito diferente do adotado pelas linguagens orientadas a objetos. O paradigma da programação estruturada é altamente orientado a dados, ou seja, você tem as estruturas de dados e, em seguida, programa instruções que atuam nesses dados. As linguagens orientadas a objetos, como a linguagem Java, combinam dados e instruções de programa em objetos.

O objeto é uma entidade autocontida que contém atributos e comportamento — e nada mais. Em vez de ter uma estrutura de dados com campos (atributos) e passar essa estrutura para toda a lógica do programa que atua nela (comportamento), em uma linguagem orientada a objetos, os dados e a lógica do programa são combinados. Essa combinação pode ocorrer em níveis muito diferentes de granularidade — de objetos de baixa granularidade, como um Number, a objetos de alta granularidade, como um serviço FundsTransfer de um grande aplicativo financeiro.

Objetos-pai e objetos-filho

Um objeto-pai serve de base para derivar objetos-filho mais complexos. O objeto-filho é semelhante ao pai, mas é mais especializado. O paradigma orientado a objetos permite reutilizar os atributos comuns e o comportamento do objeto-pai, incluindo nos seus objetos-filho os atributos e o comportamento que são diferentes. (Você saberá mais sobre a herança na próxima seção este tutorial.)

Comunicação e coordenação de objetos

Os objetos "conversam" com outros objetos enviando mensagens (chamadas de método na linguagem Java). Além disso, em um aplicativo orientado a objetos, o código do programa coordena as atividades entre objetos para realizar tarefas dentro do contexto do domínio de aplicativo específico. (No paradigma model view controller, o código do programa controlador é o Controller. Consulte a seção Recursos para saber mais sobre MVC.)

Resumo sobre objetos

Um objeto bem-escrito:

  • Tem limites bem definidos
  • Realiza um conjunto finito de atividades
  • Conhece somente os seus dados e qualquer outro objeto que seja necessário para realizar as suas atividades

Basicamente, o objeto é uma entidade separada que tem somente as dependências necessárias em outros objetos para realizar as suas tarefas.

Agora você verá qual é a aparência de um objeto.

O objeto Person

Começarei com um exemplo baseado em um cenário comum de desenvolvimento de aplicativos: um indivíduo que é representado por um objeto Person .

Voltando para a definição de objeto, você sabe que um objeto tem dois elementos principais: atributos e comportamento. Você verá como esses elementos se aplicam ao objeto Person .

Atributos

Quais atributos uma pessoa pode ter? Estes são atributos comuns:

  • Nome
  • Idade
  • Altura
  • Peso
  • Cor dos olhos
  • Sexo

Você pode pensar em outros (e incluir mais atributos posteriormente), mas essa lista é um bom começo.

Comportamento

Uma pessoa de verdade pode fazer todo tipo de coisa, mas os comportamentos de objeto geralmente estão relacionados a algum contexto de aplicativo. Em um contexto de aplicativo de negócios, por exemplo, é possível que você queira perguntar ao seu objeto Person "Qual é a sua idade?" Respondendo, Person diria a você o valor do seu atributo Age .

Uma lógica mais completa pode estar oculta dentro do objeto Person mas, por enquanto, suponha que Person tem o comportamento de responder estas perguntas:

  • Qual é o seu nome?
  • Qual é a sua idade?
  • Qual é a sua altura?
  • Qual é o seu peso?
  • Qual é a cor dos seus olhos?
  • Qual é o seu sexo?

Estado e cadeia de caracteres

Estado é um conceito importante na OOP. O estado de um objeto é representado em qualquer ponto no tempo pelo valor dos seus atributos.

No caso de Person, o estado é definido por atributos como nome, idade, altura e peso. Se você quisesse apresentar uma lista de vários desses atributos, poderia fazer isso usando uma classe String que abordarei mais adiante no tutorial.

Em conjunto, os conceitos de estado e cadeia de caracteres permitem perguntar para Person: diga quem você é dando-me uma listagem (String) dos seus atributos.


Princípios de OOP

Se você tem experiência com programação estruturada, é possível que a proposta de valor da OOP ainda não esteja clara. Afinal, os atributos de uma pessoa e a lógica para recuperar (e converter) os valores poderiam ser escritos em C ou COBOL. Esta seção esclarece os benefícios do paradigma da OOP explicando os gs que a definem: encapsulação, herança e polimorfismo.

Encapsulação

Lembre-se de que o objeto é, acima de tudo, isolado (autocontido). Isso é o princípio da encapsulação em ação. Oculto é outro termo que às vezes se usa para expressar a característica autocontida e protegida dos objetos.

Independentemente da terminologia, o importante é que o objeto mantém um limite entre o seu estado e comportamento e o ambiente externo. Assim como os objetos no mundo real, os objetos usados na programação têm vários tipos de relacionamentos com categorias diferentes dos objetos nos aplicativos que os usam.

Na plataforma Java, é possível usar especificadores de acesso (que eu apresentarei mais adiante no tutorial) para mudar a característica dos relacionamentos de objetos de public para private. O acesso público é aberto, ao passo que, no acesso privado, os atributos do objeto só podem ser acessados dentro do próprio objeto.

O limite entre público/privado faz cumprir o princípio de encapsulação da programação orientada a objetos. Na plataforma Java, é possível variar a força desse limite de forma específica para cada objeto, dependendo de um sistema de confiança. A encapsulação é um recurso poderoso da linguagem Java.

Herança

Na programação estruturada, é comum copiar uma estrutura, dar um nome novo a ela e incluir ou modificar os atributos que formam a nova entidade (como um registro Account ) diferente da fonte original. Com o tempo, essa abordagem gera uma grande quantidade de código duplicado, que pode gerar problemas de manutenção.

A OOP apresenta o conceito de herança, pelo qual objetos especializados — sem código adicional — podem "copiar" os atributos e o comportamento dos objetos de origem que eles especializam. Se há necessidade de alterar alguns desses atributos ou comportamentos, você simplesmente os substitui. Você só altera o que for necessário para criar objetos especializados. Como você aprendeu na seção Conceitos de programação orientada a objetos , o objeto de origem é chamado de pai, e a nova especialização é chamada de filho.

Herança em ação

Suponha que você esteja escrevendo um aplicativo de recursos humanos e queira usar o objeto Person como base de um novo objeto chamado Employee. Por ser filho de Person, , Employee teria todos os atributos de um objeto Person , juntamente com objetos adicionais, como:

  • Número de identificação do contribuinte
  • Data de admissão
  • Salário

A herança facilita a criação da nova classe Employee do objeto sem precisar copiar todo o código dePerson manualmente ou fazer a manutenção do mesmo.

Você verá vários exemplos de herança em programação Java mais adiante no tutorial, principalmente na Parte 2.

Polimorfismo

O polimorfismo é um conceito mais difícil de entender do que a encapsulação e a herança. Basicamente, significa que os objetos que pertencem à mesma ramificação da hierarquia, quando são enviados à mesma mensagem (ou seja, quando recebem a ordem de fazer a mesma coisa), podem manifestar o comportamento de forma diferente.

Para entender como o polimorfismo se aplica a um contexto de aplicativo de negócios, volte para o exemplo de Person . Lembre-se de que pediu para Person formatar os seus atributos em uma String? O polimorfismo permite que Person represente os seus atributos de várias formas, dependendo do tipo de Person que ele é.

O polimorfismo é um dos conceitos mais complexos da OOP na plataforma Java e está fora do escopo de um tutorial introdutório. Consulte a seção Recursos se quiser saber mais sobre o polimorfismo.


Iniciação à linguagem Java

A linguagem Java: não é puramente orientada a objetos

A linguagem Java permite criar objetos de primeira classe, mas nem tudo na linguagem é um objeto. Duas qualidades diferenciam a linguagem Java de linguagens puramente orientadas a objetos como o Smalltalk. Primeiro, a linguagem Java é uma mistura de objetos e tipos primitivos. Em segundo lugar, permite escrever um código que expõe o funcionamento de um objeto a qualquer outro objeto que o use.

A linguagem Java oferece as ferramentas necessárias para seguir princípios corretos de OOP e produzir um código orientado a objetos correto. Como o Java não é puramente orientado a objetos, é necessário ter disciplina em relação à forma de escrever o código — a linguagem não o obriga a fazer a coisa certa; portanto, é necessário fazer isso por conta própria. (A última seção deste tutorial, Escrevendo um bom código Java, dá dicas.)

Seria impossível apresentar toda a sintaxe da linguagem Java em um único tutorial. O restante da Parte 1 foca os fundamentos da linguagem, oferecendo a você conhecimento e prática suficientes para escrever programas simples. A OOP se baseia em objetos; portanto, esta seção começa com dois tópicos especialmente relacionados à manipulação de objetos na linguagem Java: palavras reservadas e a estrutura de um objeto Java.

Palavras reservadas

Como qualquer linguagem de programação, a linguagem Java designa certas palavras que são especiais para o compilador e, por serem especiais, não é permitido usá-las para dar nomes às construções em Java. A lista de palavras reservadas é surpreendentemente curta:

  • abstract
  • assert
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • class
  • const
  • continue
  • default
  • do
  • double
  • else
  • enum
  • extends
  • final
  • finally
  • float
  • for
  • goto
  • if
  • implements
  • import
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • strictfp
  • super
  • switch
  • synchronized
  • this
  • throw
  • throws
  • transient
  • try
  • void
  • volatile
  • while

Note que true, false e null não são, tecnicamente, palavras reservadas. Embora sejam literais, eu as incluí na lista porque não é permitido usá-las para dar nome a construções em Java.

Uma das vantagens de programar com um IDE é que ele pode usar coloração de sintaxe nas palavras reservadas, como você verá mais adiante neste tutorial.

Estrutura de um objeto Java

Lembre-se de que um objeto é uma entidade isolada que contém atributos e comportamento. Isso significa que ele tem um limite bem definido e um estado e pode fazer coisas quando o pedido é feito corretamente. Todas as linguagens orientadas a objetos têm regras para a definição de objetos.

Na linguagem Java, os objetos são definidos como mostra a Listagem 1:

Listagem 1. Definição de objeto
package packageName;
import ClassNameToImport;
accessSpecifier class ClassName {
  accessSpecifier dataType variableName [= initialValue];
  accessSpecifier ClassName([argumentList]) {
    constructorStatement(s)
  }
  accessSpecifier returnType methodName([argumentList]) {
    methodStatement(s)
  }
  // This is a comment
  /* This is a comment too */
  /* This is a
     multiline
     comment */
}

A Listagem 1 contém vários tipos de construções, que eu diferenciei pela formatação da fonte. As construções mostradas em negrito (que você encontra na lista de palavras reservadas) são literais; em qualquer definição de objeto, devem ser exatamente o que são aqui. Os nomes que dei às outras construções descrevem os conceitos que representam. Explicarei todas as construções detalhadamente no restante desta seção.

Nota: Na Listagem 1 e em alguns outros exemplos de código, os colchetes retos indicam que as construções dentro deles não são obrigatórias. Os colchetes propriamente ditos (diferentemente de { e }) não fazem parte da sintaxe Java.

Comentários no código

Observe que a Listagem 1 também inclui algumas linhas de comentário:

  // This is a comment
  /* This is a comment too */
  /* This is a
     multiline
     comment */

Praticamente todas as linguagens de programação permitem que o programador inclua comentários para ajudar a documentar o código. A sintaxe Java permite comentários de linha única e multilinhas. Os comentários de linha única devem estar contidos em uma linha, embora seja possível usar comentários de linha única adjacentes para formar um bloco. Um comentário multilinhas começa com /*, deve terminar com */ e pode ter qualquer número de linhas.

Você saberá mais sobre comentários quando chegar à seção deste tutorial Escrevendo um bom código Java .

Empacotando objetos

A linguagem Java permite escolher os nomes dos objetos, como Account, Person ou LizardMan. Às vezes, é possível que você acabe usando o mesmo nome para expressar dois conceitos ligeiramente diferentes. Isso é conhecido como colisão de nomes e acontece com frequência. A linguagem Java usa pacotes para resolver esses conflitos.

Um pacote Java é um mecanismo para fornecer um namespace — uma área encapsulada na qual os nomes são exclusivos mas, fora dela, podem não ser. Para identificar uma construção de forma exclusiva, é necessário qualificá-la totalmente, incluindo o seu namespace.

Os pacotes também oferecem um jeito legal de desenvolver aplicativos mais complexos em unidades isoladas de funcionalidade.

Definição de pacote

Para definir um pacote, você usa a palavra-chave package seguida por um nome válido de pacote e terminada por um ponto e vírgula. Frequentemente, os nomes de pacotes são separados por pontos e seguem este esquema de fato :

package orgType.orgName.appName.compName;

Essa definição de pacote se divide da seguinte forma:

  • orgType é o tipo de organização, como com, orgou net.
  • orgName é o nome do domínio da organização, como makotogroup, sunou ibm.
  • appName é o nome (abreviado) do aplicativo.
  • compName é o nome do componente.

A linguagem Java não obriga você a seguir essas convenções de pacote. Na verdade, nem sequer é necessário especificar um pacote; nesse caso, todos os objetos devem ter nomes de classe exclusivos e residirão no pacote padrão. A boa prática é definir todas as classes Java em pacotes. Você seguirá essa convenção ao longo deste tutorial.

Instruções de importação

A seguir, na definição de objeto (em referência à Listagem 1) vem a instrução de importação. A instrução de importação diz ao compilador Java onde encontrar as classes que você menciona no código. Qualquer objeto que não seja trivial usa outros objetos para alguma funcionalidade, e a instrução de importação é a forma de informar o compilador Java sobre eles.

Geralmente, a instrução de importação é assim:

import ClassNameToImport;

Você especifica a palavra-chave import seguida pela classe que você quer importar, seguida por um ponto e vírgula. O nome de classe deve ser totalmente qualificado, ou seja, deve incluir o seu pacote.

Para importar todas as classes dentro de um pacote, pode-se colocar .* depois do nome do pacote. Por exemplo: esta instrução importa todas as classes do pacote com.makotogroup :

import com.makotogroup.*;

Entretanto, a importação de um pacote inteiro pode deixar o seu código menos legível; sendo assim, eu recomendo que você só importe as classes que forem necessárias.

O Eclipse simplifica as importações

Ao escrever código no editor do Eclipse, é possível digitar o nome da classe que você quer usar, seguido por Ctrl+Shift+O. O Eclipse verifica quais são as importações necessárias e as inclui automaticamente. Se o Eclipse encontra duas classes com o mesmo nome, ele exibe uma caixa de diálogo perguntando em qual classe você deseja incluir as importações.

Declaração de classe

Para definir um objeto na linguagem Java, é necessário declarar uma classe. A classe é como um modelo do objeto, como se fosse um cortador de massa. A classe define a estrutura básica do objeto e, no tempo de execução, o aplicativo cria uma instância do objeto. O termo objeto frequentemente é usado como sinônimo da palavra classe. Para ser mais preciso, a classe define a estrutura da coisa da qual o objeto é uma instância.

A Listagem 1 inclui esta declaração de classe:

accessSpecifier class ClassName {
  accessSpecifier dataType variableName [= initialValue];
  accessSpecifier ClassName([argumentList]) {
    constructorStatement(s)
  }
  accessSpecifier returnType methodName([argumentList]) {
    methodStatement(s)
  }
}

O accessSpecifier de uma classe pode ter vários valores, mas na maior parte do tempo é public. Você verá os outros valores de accessSpecifier em breve.

Convenções de nomenclatura de classe

É possível nomear as classes praticamente do jeito que você quiser, mas a convenção é usar caixa alternante: comece com letra maiúscula, comece cada palavra concatenada com letra maiúscula e deixe todas as outras letras minúsculas. Os nomes de classe só podem conter letras e números. O cumprimento dessas diretrizes garante que o seu código seja mais acessível aos outros desenvolvedores que seguem as mesmas convenções.

As classes podem ter dois tipos de membros: variáveis e métodos.

Variáveis

Os valores das variáveis de uma determinada classe distinguem cada instância dessa classe e definem o seu estado. Frequentemente, esses valores são chamados de variáveis de instância. Uma variável tem:

  • Um accessSpecifier
  • Um dataType
  • Um variableName
  • Opcionalmente, um initialValue

Os possíveis valores de accessSpecifier são:

Variáveis públicas

Não é recomendável usar variáveis públicas mas, em casos extremamente raros, isso pode ser necessário — por isso, a opção existe. A plataforma Java não limita os seus casos de uso; portanto, cabe a você ser disciplinado em relação ao uso de boas convenções de codificação, mesmo se for "tentado" a não fazer isso.

  • public: qualquer objeto de qualquer pacote pode ver a variável. (Jamais use esse valor.)
  • protected: qualquer objeto definido no mesmo pacote, ou uma subclasse (definida em qualquer pacote), pode ver a variável.
  • Sem especificador (também conhecido como acesso amigável ou privado de pacote ): somente objetos cujas classes são definidas no mesmo pacote podem ver a variável.
  • private: somente a classe que contém a variável pode vê-la.

O dataType de uma variável depende do tipo de variável — pode ser um tipo primitivo ou outro tipo de classe (você também verá mais sobre isso mais adiante).

O variableName é você quem determina mas, por convenção, os nomes de variável usam a convenção de caixa alternante descrita anteriormente, mas começam com letra minúscula. (Esse estilo também é conhecido como lowerCamelCase.)

Por enquanto, não se preocupe com o initialValue . Basta saber que é permitido inicializar uma variável de instância quando você a declara. (Caso contrário, o compilador gera um padrão para você, que será configurado quando a classe for instanciada.)

Exemplo: definição de classe para Person

Antes de passar aos métodos, darei um exemplo que resume tudo o que você aprendeu até agora. A Listagem 2 é uma definição de classe para Person:

Listagem 2. Definição de classe básica para Person
package com.makotogroup.intro;

public class Person {
  private String name;
  private int age;
  private int height;
  private int weight;
  private String eyeColor;
  private String gender;
}

A definição de classe básica para Person não é muito útil neste ponto porque define somente os seus atributos (e apenas os privados).

Para ficar mais interessante, a classe the Person precisa de um comportamento — ou seja, de métodos.

Métodos

Os métodos de uma classe definem o seu comportamento. Às vezes esse comportamento não é nada mais do que retornar o valor atual de um atributo. Em outras ocasiões, o comportamento pode ser muito complexo.

Basicamente, há duas categorias de métodos: construtores e todos os outros métodos — que têm vários tipos. Um método construtor é usado somente para criar uma instância de uma classe. Outros tipos de métodos podem ser usados para praticamente qualquer comportamento de aplicativo.

Voltando à Listagem 1, ela mostra o modo de definir a estrutura de um método, que inclui coisas como estas:

  • accessSpecifier
  • returnType
  • methodName
  • argumentList

A combinação desses elementos estruturais na definição de um método é conhecida como a sua assinatura.

A seguir, você verá mais detalhes dos dois tipos de métodos, começando com os construtores.

Métodos de construtor

Os construtores permitem especificar como instanciar uma classe. A Listagem 1 mostra a sintaxe da declaração do construtor de forma abstrata; a sintaxe aparece novamente na Listagem 3:

Listagem 3. Sintaxe da declaração do construtor
accessSpecifier ClassName([argumentList]) {
  constructorStatement(s)
}

Os construtores são opcionais

Se você não fornece um construtor, o compilador fornecerá um para você, chamado de construtor padrão (ou(no-argument). Se você fornece um construtor que não é um no-argument (no-arg), o compilador não gerará um construtor para você.

O accessSpecifier de um construtor é igual ao das variáveis. O nome do construtor deve corresponder ao nome da classe. Portanto, se a classe tem o nome Person, o nome do construtor também deve ser Person.

No caso de qualquer construtor que não seja o padrão, você passa uma argumentList, que é um ou mais do seguinte:

argumentType argumentName

Os argumentos de uma argumentList são separados por vírgulas, e não há argumentos com nomes iguais. argumentType é um tipo primitivo ou outro tipo de classe (a mesma coisa que ocorre com os tipos de variável).

Definição de classe com um construtor

Agora você verá o que acontece ao incluir o recurso de criar um objeto Person de duas formas: usando um construtor no-arg e inicializando uma lista parcial de atributos.

A Listagem 4 mostra como criar construtores e como usar a argumentList:

Listagem 4. Definição da classe Person com um construtor
package com.makotogroup.intro;
public class Person {
  private String name;
  private int age;
  private int height;
  private int weight;
  private String eyeColor;
  private String gender;
  public Person() {
    // Nothing to do...
  }
  
public Person(String name, int age, int height, String eyeColor, String gender) {
    this.name = name;
    this.age = age;
    this.height = height;
    this.weight = weight;
    this.eyeColor = eyeColor;
    this.gender = gender;
  }
}

Observe o uso da palavra-chave this para fazer as atribuições de variáveis na Listagem 4. Esta é a forma "taquigráfica" no Java que significa "este objeto", e deve ser usada ao fazer referência a duas variáveis com nomes iguais (como neste caso, no qual "age", por exemplo, é um parâmetro de construtor e uma variável de classe) e ajuda o compilador a eliminar a ambiguidade da referência.

O objeto Person está ficando mais interessante, mas precisa de mais comportamento. Para isso, são necessários mais métodos.

Outros métodos

O construtor é um tipo específico de método que tem uma função específica. Da mesma forma, vários outros tipos de métodos executam funções específicas em programas Java. A exploração dos outros métodos começa nesta seção e continua ao longo de todo o tutorial.

Voltando à Listagem 1, eu mostrei como declarar um método:

accessSpecifier returnType methodName([argumentList]) {
  methodStatement(s)
}

Outros métodos são muito semelhantes aos construtores, com algumas exceções. Primeiro: é permitido dar o nome que você quiser aos outros métodos (embora haja regras sobre isso, obviamente). Eu recomendo as seguintes convenções:

  • Comece com letra minúscula.
  • Não use números, a não ser que sejam absolutamente necessários.
  • Use somente caracteres alfabéticos.

Em segundo lugar, diferentemente dos construtores, os outros métodos têm um tipo de retorno opcional.

Outros métodos de Person

Munido dessas informações básicas, é possível ver o que acontece na Listagem 5 quando você inclui mais alguns métodos no objeto Person .(Omiti os construtores por uma questão de concisão.)

Listagem 5. Person com alguns novos métodos
package com.makotogroup.intro;

public class Person {
  private String name;
  private int age;
  private int height;
  private int weight;
  private String eyeColor;
  private String gender;

  public String getName() { return name; }
  public void setName(String value) { name = value; }
  // Other getter/setter combinations...
}

Observe o comentário na Listagem 5 sobre combinações"getter/setter". Você trabalhará mais com getters e setters adiante no tutorial. Por enquanto, basta saber que getter é um método para recuperar o valor de um atributo e setter é um método para modificar esse valor. Mostrei somente uma combinação getter/setter (referente ao atributo Name ), mas seria possível definir mais de forma semelhante.

Observe na Listagem 5 que, se um método não retorna um valor, é necessário informar o compilador especificando o tipo de retorno void na sua assinatura.

Métodos estáticos e de instância

De forma geral, há dois tipos de métodos (não construtores): métodos de instância e métodos estáticos. O comportamento dos métodos de instância depende do estado da instância de um objeto específico. Os métodos estáticos também são conhecidos comométodos de classes, porque o comportamento deles não depende do estado de nenhum objeto único. O comportamento de um método estático acontece no nível da classe.

Os métodos estáticos são usados, em grande parte, por conveniência; são uma forma de ter métodos globais (como na linguagem C) e, ao mesmo tempo, manter o código propriamente dito agrupado com a classe que precisa dele.

Por exemplo: ao longo deste tutorial, você usará a classe do JDK chamada Logger para realizar a saída das informações para o console. Para criar uma instância da classe Logger , você não instancia uma classe Logger ; em vez disso, chama um método estático denominado getLogger().

A sintaxe para chamar um método estático é diferente da sintaxe usada para chamar um método em uma instância do objeto. Você também usa o nome da classe que contém o método estático, como se mostra nesta chamada:

Logger l = Logger.getLogger("NewLogger");

Para chamar um método estático, você não precisa de uma instância do objeto, somente do nome da classe.


O seu primeiro objeto Java

Está na hora de juntar tudo o que você aprendeu nas seções anteriores e começar a escrever código. Esta seção repassa o processo de declarar uma classe e incluir variáveis e métodos nela usando o Eclipse Package Explorer. Você aprenderá a usar a classe Logger para acompanhar o comportamento do seu aplicativo e a usar o método main() como uma rotina de teste.

Criando um pacote

Vá para a perspectiva Package Explorer do Eclipse, se ainda não estiver lá. Você irá se preparar para criar a sua primeira classe Java. A primeira etapa é criar um local para a classe morar. Os pacotes são construções de namespace, mas também correspondem, de forma conveniente, diretamente à estrutura de diretório do sistema de arquivos.

Em vez de usar o pacote padrão (o que quase sempre não é uma boa ideia), você criará um especificamente para o código que está escrevendo. Clique em File > New > Package para acessar o assistente Java Package, mostrado na Figura 4:

Figura 4. O assistente Java Package do Eclipse
O assistente Java Package do Eclipse

Digite com.makotogroup.intro na caixa de texto Name e clique em Finish. Você verá o novo pacote criado no Package Explorer.

Declarando a classe

Há mais de uma forma de criar uma classe no Package Explorer, mas o jeito mais fácil é clicar com o botão direito no pacote que você acabou de criar e escolher New > Class.... Você verá caixa de diálogo New Class.

Na caixa de texto Name , digite Person. Em Which method stubs would you like to create?, marque public static void main(String[] args). (em breve você verá por que fez isso.) Em seguida, clique em Finish.

A nova classe aparece na janela de edição. Eu recomendo fechar algumas visualizações da aparência padrão para facilitar a visualização do código de origem, como mostra a Figura 5:

Figura 5. Uma área de trabalho bem organizada
Uma área de trabalho bem organizada

O Eclipse gera uma classe shell para você e inclui a instrução do pacote na parte superior, junto com o método main() que você solicitou e os comentários que você vê. Agora você só precisa preencher a classe. É possível configurar a geração de novas classes no Eclipse por meio de Window > Preferences > Java > Code Style > Code Templates. Por uma questão de simplicidade, você usará a geração de códigos padrão do Eclipse.

Na Figura 5, observe o asterisco (*) ao lado do novo arquivo de código de origem, que indica que eu fiz uma modificação. Observe também que o código não foi salvo. Em seguida, note que eu cometi um erro ao declarar o atributo Name : declarei que o tipo de Name é Strin. O compilador não localizou uma referência a essa classe e a sinalizou como erro de compilação (colocou uma linha vermelha ondulada debaixo de Strin). Obviamente, posso corrigir o erro acrescentando um g no final de Strin. Esta é apenas uma pequena demonstração da vantagem de usar um IDE para o desenvolvimento de software, em comparação com as ferramentas de linha de comando.

Incluindo variáveis de classe

Na Listagem 4, você começou a preencher a classe Person , mas eu não expliquei uma boa parte da sintaxe. Agora eu definirei formalmente como incluir variáveis de classe.

Lembre-se de que uma variável tem um accessSpecifier, um dataType, um variableName e, opcionalmente, um initialValue. Anteriormente, você viu de forma sucinta como se define o accessSpecifier e o variableName. Agora você verá o dataType que uma variável pode ter.

Um dataType pode ser um tipo primitivo ou uma referência a outro objeto. Por exemplo: observe que Age é um int (um tipo primitivo) e Name é um String (um objeto). O JDK vem com várias classes úteis como java.lang.String, e aquelas do pacote java.lang não precisam ser importadas (uma cortesia taquigráfica do compilador Java). No entanto, independentemente de dataType ser uma classe do JDK como String ou uma classe definida pelo usuário, a sintaxe é basicamente a mesma.

A Tabela 1 mostra os oito tipos de dados primitivos que provavelmente você verá com mais frequência, inclusive os valores-padrão que as primitivas adotam se você não inicializa explicitamente o valor de uma variável de membro:

Tabela 1. Tipos de dados primitivos
TipoTamanhoValor-padrãoIntervalo de valores
booleann/dfalsetrue ou false
byte8 bits0-128 a 127
char16 bits(sem assinatura)\u0000' \u0000' a \uffff' ou 0 a 65535
short16 bits0-32768 a 32767
int32 bits0-2147483648 a 2147483647
long64 bits0-9223372036854775808 a 9223372036854775807
float32 bits0.01.17549435e-38 a 3.4028235e+38
double64 bits0.04.9e-324 a 1.7976931348623157e+308

Criação de log integrada

Antes de passar para a codificação, é necessário saber como os programas informam o que estão fazendo.

A plataforma Java inclui o pacote java.util.logging , um mecanismo integrado de criação de log para coletar informações do programa deforma legível. Os criadores de logs são entidades nomeadas que podem ser criadas por meio de uma chamada de método estático à classe Logger , da seguinte forma:

import java.util.logging.Logger;
//. . .
Logger l = Logger.getLogger(getClass().getName());

Ao chamar o método getLogger() , você passa para ele um String. Por enquanto, habitue-se a passar o nome da classe na qual o código que você está escrevendo está localizado. A partir de qualquer método regular (ou seja, não estático), o código acima sempre fará referência ao nome da classe e passará esse nome aoLogger.

Se você está fazendo uma chamada a Logger dentro de um método estático, somente faça referência ao nome da classe na qual você está:

Logger l = Logger.getLogger(Person.class.getName());

Neste exemplo, o código dentro do qual você está é a classe Person ; portanto, você faz referência a um literal especial chamado class que recupera o objeto Class (você verá mais sobre isso mais adiante) e obtém o seu atributo Name .

A seção deste tutorial chamada Escrevendo um bom código Java inclui uma dica sobre como não criar logs.

Usando main() como uma rotina de teste

main() é um método especial que pode ser incluído em qualquer classe para que o JRE possa executar o seu código. Não é obrigatório que a classe tenha um método main()— na verdade, a maioria das classes nunca terá — e cada classe pode ter, no máximo, um método main() .

main() é um método bastante útil, porque oferece uma rotina de teste rápida para a classe. No desenvolvimento corporativo, você usaria bibliotecas de teste; para os fins deste tutorial, usará o main() como a sua rotina de teste.

Entre no editor de código de origem do Eclipse referente a Person e inclua código para que ele fique semelhante à Listagem 4. O Eclipse tem um gerador de código útil para gerar getters e setters (entre outras coisas). Para experimentá-lo, coloque o cursor do mouse na definição da classe Person (ou seja, na palavra Person na definição de classe) e vá para Source > Generate Getters and Setters.... Quando a caixa de diálogo abrir, clique em Select All, como mostra a Figura 6:

Figura 6. O Eclipse gerando getters e setters
O Eclipse gerando getters e setters

Para o ponto de inserção, escolha Last member e clique em OK. Observe que os getters e setters aparecem depois do método main() .

Há mais coisas relacionadas ao main()

Agora você incluirá código no main() para permitir a instanciação de um Person, configurar alguns atributos e, em seguida, imprimi-los para o console.

Comece incluindo um construtor em Person. Digite o código da Listagem 6 na sua janela de origem, logo abaixo da parte superior da definição de classe (a linha imediatamente abaixo de public class Person ()):

Listagem 6. Construtor Person
public Person(String name, int age, int height, int weight, String eyeColor, 
                String gender) {
    this.name = name;
    this.age = age;
    this.height = height;
    this.weight = weight;
    this.eyeColor = eyeColor;
    this.gender = gender;
  }

Certifique-se de que não haja linhas onduladas indicando erros de compilação.

Em seguida, vá para o método main() e deixo-o semelhante à Listagem 7:

Listagem 7. O método main()
public static void main(String[] args) {
  Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
  Logger l = Logger.getLogger(Person.class.getName());
  l.info("Name: " + p.getName());
  l.info("Age:" + p.getAge());
  l.info("Height (cm):" + p.getHeight());
  l.info("Weight (kg):" + p.getWeight());
  l.info("Eye Color:" + p.getEyeColor());
  l.info("Gender:" + p.getGender());
}

Por enquanto, não se preocupe com a classe Logger . Insira o código do jeito que está na Listagem 7. Agora você está pronto para executar o seu primeiro programa Java.

Executando código no Eclipse

Para executar um aplicativo Java de dentro do Eclipse, selecione a classe que você quer executar, que deve ter um método main() . No momento, você só tem uma classe — e essa classe tem um método main()— Portanto, selecione Person e, em seguida, clique no ícone Run (que é verde e tem uma pequena seta triangular apontando para a direita). Quando for solicitado, selecione para executar Person como um aplicativo Java, relaxe e veja o que acontece. Você deve ver algo parecido com a captura de tela da Figura 7:

Figura 7. Veja a execução Person
Veja a execução Person

Observe que a visualização Console abre automaticamente e mostra a saída de Logger . Também selecionei a visualização Outline no painel esquerdo, que revela a estrutura básica da classe Person em uma visão rápida.


Incluindo comportamento em um objeto Java

Person está indo bem até agora, mas poderia ter um pouco mais de comportamento para ficar mais interessante. Como você já sabe, criar comportamento significa incluir métodos. Esta seção aborda mais detalhadamente os métodos acessadores — , ou seja, os getters e setters que você já viu em ação. Você também aprenderá a sintaxe usada para chamar métodos.

Métodos acessadores

Para encapsular os dados de uma classe em relação aos outros objetos, você declara que as suas variáveis são private e, em seguida, fornece métodos acessadores. Como você sabe, um getter é um método acessador que recupera o valor de um atributo; um setter é um método acessador para modificar esse valor. A nomenclatura dos acessadores segue uma convenção rigorosa conhecida como padrão JavaBeans, segundo o qual qualquer atributo Foo tem um getter chamado getFoo() e um setter chamado setFoo().

O padrão JavaBeans é tão comum que o suporte a ele está integrado ao IDE Eclipse. Inclusive, você já o viu em ação — quando gerou os getters e setters para Person na seção anterior.

Os acessadores seguem estas diretrizes:

  • O atributo em si sempre é declarado com acesso private .
  • O especificador de acesso para getters e setters é public.
  • Os getters não tomam nenhum parâmetro e retornam um valor cujo tipo é igual ao do atributo que ele acessa.
  • As configurações só tomam um parâmetro, do tipo do atributo, e não retornam nenhum valor.

Declarando acessadores

Sem dúvida, a forma mais fácil de declarar acessadores é deixar o Eclipse fazer isso para você, como mostra a Figura 6.. No entanto, você também deve saber codificar manualmente um par getter/setter. Suponha que você tem um atributo, Foo, cujo tipo é java.lang.String. A declaração completa referente a ele(de acordo com as diretrizes para acessadores) seria:

private String foo;
public String getFoo() {
  return foo;
}
public void setFoo(String value) {
  foo = value;
}

Talvez você tenha percebido de imediato que o valor de parâmetro que foi passado ao setter tem um nome diferente do que ele teria caso tivesse sido gerado pelo Eclipse. Esta é a minha convenção, e eu a recomendo aos outros desenvolvedores. Nas raras vezes em que eu codifico um setter manualmente, sempre uso o nome value como o valor de parâmetro para o setter. Isso me faz lembrar de que eu codifiquei manualmente o setter. Já que eu geralmente deixo o Eclipse gerar getters e setters para mim, tem que haver um bom motivo para eu não fazer isso. O uso de value como o valor de parâmetro do setter me faz lembrar que o setter é especial. (Os comentários do código também podem fazer isso.)

Chamando métodos

Chamar (invocar) métodos é fácil. Você viu na Listagem 7 como chamar os vários getters de Person para retornar os seus valores. Agora eu irei formalizar a mecânica das chamadas de método.

Chamada de método com e sem parâmetros

Para chamar um método em um objeto, é preciso ter uma referência a esse objeto. A sintaxe da chamada de método inclui a referência do objeto, um ponto literal, o nome do método e quaisquer parâmetros que precisem ser passados:

objectReference.someMethod();
objectReference.someOtherMethod(parameter);

Esta é uma chamada de método sem parâmetros:

Person p = /*obtain somehow */;
p.getName();

E esta é uma chamada de método com parâmetros(acessando o atributo Name de Person):

Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");

Lembre-se de que os construtores também são métodos. E é possível separar os parâmetros com espaços e novas linhas. O compilador Java não dá importância a isso. As duas chamadas de método a seguir são idênticas:

new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
new Person("Joe Q Author", 
        42, 
        173, 
        82, 
        "Brown", 
        "MALE");

Chamada de método aninhada

As chamadas de método também podem ser aninhadas:

Logger l = Logger.getLogger(Person.class.getName());
l.info("Name: " + p.getName());

Aqui você está passando o valor de retorno de Person.class.getName() para o método getLogger() . Lembre-se de que a chamada do método getLogger() é uma chamada de método estático — portanto, a sintaxe é ligeiramente diferente. (Não é necessário ter uma referência a Logger para fazer a chamada; em vez disso, você só usa o nome da classe em si como o lado esquerdo da chamada.)

Na verdade, a chamada de métodos se resume a isso.


Cadeias de caracteres e operadores

Até agora, o tutorial apresentou diversas variáveis do tipo String, mas não deu muitas explicações. Nesta seção, saiba mais sobre as cadeias de caracteres e veja quando e como usar os operadores.

Cadeias de caracteres

A manipulação de cadeias de caracteres em C é trabalhosa porque é necessário manipular arrays terminados em nulls, formados por caracteres de 8 bits. Na linguagem Java, as cadeias de caracteres são objetos de primeira classe do tipo String, com métodos que ajudam a manipulá-las. (A maior semelhança entre o código Java e a linguagem C em termos de cadeias de caracteres é o tipo de dados primitivos char , que pode conter um único caractere Unicode, como a.)

Você já viu como instanciar um objeto String e configurar o valor dele(na Listagem 5), mas há várias outras formas de fazer isso. Estas são algumas formas de criar uma instância de String com o valor hello:

String greeting = "hello";
greeting = new String("hello");

Como Strings são objetos de primeira classe na linguagem Java, é possível usar new para instanciá-los. A configuração de uma variável do tipo String tem o mesmo resultado, porque a linguagem Java cria um objeto String para conter o literal e, em seguida, designa esse objeto para a variável de instância.

Concatenando cadeias de caracteres

É possível fazer várias coisas com String, e a classe tem vários métodos úteis. Sem usar um método sequer, você já fez algo interessante com duas Strings ao concatená-las (combiná-las):

l.info("Name: " + p.getName());

O sinal de mais (+) indica concatenação de String na linguagem Java. (Realizar esse tipo de concatenação dentro de um loop prejudica um pouco o desempenho, mas por enquanto não é necessário se preocupar com isso.)

Exemplo de concatenação

Vamos tentar concatenar String dentro da classe Person . Neste ponto, você tem uma variável de instância name , mas seria bom ter firstName e lastName. Em seguida, seria possível concatená-las quando outro objeto solicitar o nome completo de Person.

A primeira coisa a fazer é incluir as novas variáveis de instância (no mesmo local do código de origem no qual name está definido atualmente):

//private String name;
private String firstName;
private String lastName;

Você não precisa mais de name , que foi substituído por firstName e lastName.

Encadeando chamadas de método

Agora é possível gerar getters e setters para firstName e lastName (como mostra a Figura 6.), remover o método setName() e alterar getName() para que fique assim:

public String getName() {
  return firstName.concat(" ").concat(lastName);
}

Esse código ilustra o encadeamento de chamadas de método. Trata-se de uma técnica usada frequentemente com objetos imutáveis como String, no qual uma modificação em um objeto imutável sempre retorna a modificação (mas não altera o original). Em seguida, você opera no valor retornado e alterado.

Operadores

Como se pode esperar, a linguagem Java trabalha com aritmética — e você já viu como designar variáveis. Agora eu irei apresentar sucintamente alguns operadores da linguagem Java dos quais você irá precisar à medida que as suas qualificações melhoram. A linguagem Java usa dois tipos de operadores:

  • Unários: só há necessidade de um operando.
  • Binários: há necessidade de dois operandos.

A Tabela 2 resume os operadores aritméticos da linguagem Java:

Tabela 2. Operadores aritméticos da linguagem Java
OperadorUsoDescrição
+a + bSoma a e b
++aPromove a paraint se for um byte, short ou char
-a - bSubtrai b de a
--aFaz a operação de negação aritmética em a
*a * bMultiplica a por b
/a / bDivide a por b
%a % bRetorna o resto da divisão de a por b (o operador de módulo)
++a++Incrementa a em 1; calcula o valor de a antes de incrementar
++++aIncrementa a em 1; calcula o valor de a depois de incrementar
--a--Decrementa a em 1; calcula o valor de a antes de decrementar
----aDecrementa a em 1; calcula o valor de a depois de decrementar
+=a += bForma taquigráfica de a = a + b
-=a -= bForma taquigráfica de a = a - b
*=a *= bForma taquigráfica de a = a * b
%=a %= bForma taquigráfica de a = a % b

Operadores adicionais

Além dos operadores da Tabela 2, você viu vários outros símbolos chamados de operadores na linguagem Java. Por exemplo:

  • Ponto (.), que qualifica nomes de pacotes e chama métodos
  • Parênteses (()), que delimitam uma lista separada por vírgula para um método
  • new, que (quando é seguido por um nome de construtor) instancia um objeto

A sintaxe da linguagem Java também inclui vários operadores que são usados especificamente para a programação condicional, ou seja, programas que respondem de forma diferente a entradas diferentes. Você verá programas desse tipo na próxima seção.


Operadores condicionais e instruções de controle

Nesta seção, aprenda sobre os vários operadores e instruções que você usará para dizer aos seus programas Java como você quer que eles ajam baseando-se em entradas diferentes.

Operadores relacionais e condicionais

A linguagem Java oferece operadores e instruções de controle que permitem tomar decisões no seu código. Muito frequentemente, uma decisão no código começa com uma expressão booleana (ou seja, expressão que avalia em termos de verdadeiro ou falso). Esses tipos de expressão usam operadores relacionais, que comparam uma expressão ou operando com outro, e operadores condicionais.

A Tabela 3 lista os operadores relacionais e condicionais da linguagem Java:

Tabela 3. Operadores relacionais e condicionais
OperadorUsoRetorna true se...
>a > ba é maior que b
>=a >= ba é maior ou igual a b
<a < ba é menor que b
<=a <= ba é menor ou igual a b
==a == ba é igual a b
!=a != ba é diferente de b
&&a && ba e b são verdadeiros, avalia condicionalmente b (se a é falso, b não é avaliado)
||a || ba ou b é verdadeiro, avalia condicionalmente b (se a é verdadeiro, b não é avaliado)
!!aa é falso
&a & ba e b são verdadeiros, sempre avalia b
|a | ba ou b é verdadeiro, sempre avalia b
^a ^ ba e b são diferentes

A instrução if

Agora que você dispõe de vários operadores, está na hora de usá-los. Esse código mostra o que acontece quando você inclui lógica no objeto acessador getHeight() de um objeto Person :

public int getHeight() {
  int ret = height;
  // If locale of the machine this code is running on is U.S.,
  if (Locale.getDefault().equals(Locale.US))
    ret /= 2.54;// convert from cm to inches
  return ret;
}

Se o código do idioma atual corresponde aos Estados Unidos (onde o sistema métrico não é usado), faz sentido converter o valor interno de altura (em centímetros) para polegadas. Esse exemplo ilustra o uso da instrução if , que avalia uma expressão booleana entre parênteses. Se a expressão é verdadeira, a instrução executa a próxima instrução.

Nesse caso, basta executar uma instrução se o Locale da máquina onde o código está executando é Locale.US. Se precisar executar mais de uma instrução, poderá usar chaves para formar uma instrução composta. Uma instrução composta agrupa várias instruções em uma — e as instruções compostas também podem conter outras instruções compostas.

Escopo das variáveis

Toda variável de um aplicativo Java tem um escopo, ou seja, namespace localizado, no qual é possível acessá-la pelo nome dentro do código. Fora desse espaço, a variável está fora de escopo, e ocorrerá um erro de compilação se você tentar acessá-la. Os níveis de escopo na linguagem Java são definidos de acordo com o local da declaração da variável, como mostra a Listagem 8:

Listagem 8. Escopo das variáveis
public class SomeClass {

  private String someClassVariable;
  public void someMethod(String someParameter) {
    String someLocalVariable = "Hello";
    if (true) {
      String someOtherLocalVariable = "Howdy";
    }
    someClassVariable = someParameter; // legal
    someLocalVariable = someClassVariable; // also legal
    someOtherLocalVariable = someLocalVariable;// Variable out of scope!
  }
  public void someOtherMethod() {
    someLocalVariable = "Hello there";// That variable is out of scope!
  }
}

Dentro de SomeClass, someClassVariable pode ser acessada por todos os métodos de instância (ou seja, não estáticos). Dentro desomeMethod, someParameter é visível, mas fora desse método não é; o mesmo vale para someLocalVariable. Dentro do bloco if , someOtherLocalVariable é declarada, fora desse bloco de if , ela está fora de escopo.

O escopo tem várias regras, mas a Listagem 8 mostra as mais comuns. Reserve alguns minutos para familiarizar-se com elas.

A instrução else

Há ocasiões no fluxo de controle de um programa nas quais você só deseja realizar uma ação se uma determinada expressão não é verdadeira. É nesses casos que o else ajuda:

public int getHeight() {
  int ret;
  if (gender.equals("MALE"))
    ret = height + 2;
  else {
    ret = height;
    Logger.getLogger("Person").info("Being honest about height...");
  }
  return ret;
}

A instrução else funciona da mesma forma que o if, já que executa somente a próxima instrução que encontra. Nesse caso, duas instruções são agrupadas em uma instrução composta(observe as chaves), que o programa executa em seguida.

Também é possível usar o else para executar uma verificação if adicional, da seguinte forma:

if (conditional) {
  // Block 1
} else if (conditional2) {
  // Block 2
} else if (conditional3) {
  // Block 3
} else {

  // Block 4
} // End

Se conditional for verdadeiro, o Block 1 é executado e o programa vai para a próxima instrução depois da chave final (indicada por // End). Se conditionalnão é verdadeiro, conditional2 é avaliado. Caso seja verdadeiro, Block 2 é executado, e o programa vai para a próxima instrução depois da última chave. Se conditional2 não é verdadeiro, o programa passa para conditional3, e assim sucessivamente. Somente se os três condicionais falhassem o Block 4 seria executado.

O operador ternário

A linguagem Java fornece um operador prático para executar verificações simples de instruções if/else . A sua sintaxe é:

(conditional) ? statementIfTrue : statementIfFalse;

Se conditional é verdadeiro, statementIfTrue é executado; caso contrário, statementIfFalse é executado. Não é permitido usar instruções compostas em nenhuma das instruções.

O operador ternário é útil quando você sabe que precisará executar uma instrução se a avaliação da condicional for verdadeira e outra instrução se não for. Os operadores ternários geralmente são usados para inicializar uma variável (como um valor de retorno), da seguinte forma:

public int getHeight() {
  return (gender.equals("MALE")) ? (height + 2) : height;
}

Os parênteses depois do ponto de interrogação acima não são obrigatórios, mas deixam o código mais legível.


Loops

Além de poder aplicar condições aos seus programas e ver resultados diferentes de acordo com os vários cenários de if/then , às vezes você quer que o seu código repita exatamente a mesma coisa várias vezes até que a tarefa seja concluída. Nesta seção, saiba mais sobre duas construções usadas para repetir o código ou executá-lo mais de uma vez: loops de for e loops de while .

O que é um loop?

O loop é uma construção de programação que executa repetidamente enquanto alguma condição (ou conjunto de condições) é atendida. Por exemplo: é possível pedir que o programa leia todos os registros até o final de um arquivo ou faça loop em todos os elementos de um array, processando cada um deles. (Você aprenderá sobre arrays na seção deste tutorial chamada Java Collections .)

Loops de for

A construção básica de loop na linguagem Java é a instruçãofor , que permite fazer iteração em um intervalo de valores para determinar quantas vezes o loop deve ser executado. A sintaxe abstrata de um loopfor é:

for (initialization; loopWhileTrue; executeAtBottomOfEachLoop) {
  statementsToExecute
}

No início do loop, a instrução de inicialização é executada (é possível separar instruções de inicialização com vírgulas). Se loopWhileTrue (uma expressão condicional de Java que deve necessariamente ser verdadeira ou falsa) seja verdadeiro, o loop será executado. Na parte inferior do loop, executeAtBottomOfEachLoop é executado.

Exemplo de um loop de for

Se você quisesse alterar um método main() para que ele executasse três vezes, poderia usar um loop de for , como mostra a Listagem 9:

Listagem 9. Um loop de for
public static void main(String[] args) {
  Logger l = Logger.getLogger(Person.class.getName());
  for (int aa = 0; aa < 3; aa++) {
    Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
    l.info("Loop executing iteration# " + aa);
    l.info("Name: " + p.getName());
    l.info("Age:" + p.getAge());
    l.info("Height (cm):" + p.getHeight());
    l.info("Weight (kg):" + p.getWeight());
    l.info("Eye Color:" + p.getEyeColor());
    l.info("Gender:" + p.getGender());
  }
}

A variável local aa é inicializada como zero no início da listagem. Essa instrução executa somente uma vez, quando o loop é inicializado. Em seguida, o loop continua três vezes e, em cada vez, aa é incrementado em um.

Como você verá mais adiante, uma sintaxe alternativa do loop de for está disponível para fazer loop em construções que implementam a interface Iterable (como arrays e outras classes do utilitário de Java). Por enquanto, só observe o uso da sintaxe do loop for na Listagem 9.

Loops while

A sintaxe de um loop while é:

while (loopWhileTrue) {
  statementsToExecute
}

Como você deve desconfiar, whileloopWhileTrue é verdadeiro; portanto, o loop é executado. Na parte superior de cada iteração (ou seja, antes da execução de qualquer instrução), a condição é avaliada. Se for verdadeira, o loop será executado. Portanto, é possível que um loop while nunca execute se a sua expressão condicional não for verdadeira pelo menos uma vez.

Olhe novamente o loop for na Listagem 9. Para comparação, a Listagem 10 o codifica usando um loop while :

Listagem 10. Um loop while
public static void main(String[] args) {
  Logger l = Logger.getLogger(Person.class.getName());
  int aa = 0;
  while (aa < 3) {
    Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
    l.info("Loop executing iteration# " + aa);
    l.info("Name: " + p.getName());
    l.info("Age:" + p.getAge());
    l.info("Height (cm):" + p.getHeight());
    l.info("Weight (kg):" + p.getWeight());
    l.info("Eye Color:" + p.getEyeColor());
    l.info("Gender:" + p.getGender());
    aa++;
  }

Como se pode ver, um loop while é um pouco mais trabalhoso que um loop for . É necessário inicializar a variável aa e também se lembrar de incrementá-la no final do loop.

Loops do... while

Se você quer um loop que sempre execute uma vez e, em seguida, verifique a sua expressão condicional, tente usar um loop do...while , como mostra a Listagem 11:

Listagem 11. Um loop do...while
int aa = 0;
do {
  Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
  l.info("Loop executing iteration# " + aa);
  l.info("Name: " + p.getName());
  l.info("Age:" + p.getAge());
  l.info("Height (cm):" + p.getHeight());
  l.info("Weight (kg):" + p.getWeight());
  l.info("Eye Color:" + p.getEyeColor());
  l.info("Gender:" + p.getGender());
  aa++;
} while (aa < 3);

A expressão condicional (aa < 3) só é verificada no final do loop.

Ramificação de loops

Em algumas ocasiões, é necessário sair de um loop antes que a expressão condicional seja falsa. Isso poderia acontecer se você estivesse fazendo uma busca em um array de Strings procurando um valor específico e, depois de localizar, os outros elementos do array não tivessem importância para você. Para as ocasiões em que você quer sair do loop , a linguagem Java fornece a instrução break , como mostra a Listagem 12:

Listagem 12. A instrução break
public static void main(String[] args) {
  Logger l = Logger.getLogger(Person.class.getName());
  int aa = 0;
  while (aa < 3) {
    if (aa == 1)
      break;
    Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
    l.info("Loop executing iteration# " + aa);
    l.info("Name: " + p.getName());
    l.info("Age:" + p.getAge());
    l.info("Height (cm):" + p.getHeight());
    l.info("Weight (kg):" + p.getWeight());
    l.info("Eye Color:" + p.getEyeColor());
    l.info("Gender:" + p.getGender());
    aa++;
  }

A instrução break leva você para a próxima instrução executável fora do loop no qual ela está localizada.

Continuação de loops

No exemplo (simplista) da Listagem 12, você quer executar o loop uma vez e sair. Também é possível ignorar uma única iteração da um loop, mas continuar executando o mesmo. Para fazer isso, você precisa da instrução continue , como mostra a Listagem 13:

Listagem 13. Uma instrução continue
public static void main(String[] args) {
Logger l = Logger.getLogger(Person.class.getName());
int aa = 0;
while (aa < 3) {
  if (aa == 1)
    continue;
  else
    aa++;
  Person p = new Person("Joe Q Author", 42, 173, 82, "Brown", "MALE");
  l.info("Loop executing iteration# " + aa);
  l.info("Name: " + p.getName());
  l.info("Age:" + p.getAge());
  l.info("Height (cm):" + p.getHeight());
  l.info("Weight (kg):" + p.getWeight());
  l.info("Eye Color:" + p.getEyeColor());
  l.info("Gender:" + p.getGender());
}

Na Listagem 13, você ignorou a segunda iteração de um loop mas passou para a terceira. continue é útil quando você está, por exemplo, processando registros e encontra um registro que não quer processar de jeito nenhum. Simplesmente ignore esse registro e passe para o próximo.


Java Collections

A maioria dos aplicativos reais lida com coleções de coisas: arquivos, variáveis, registros de arquivos, conjuntos de resultados de banco de dados, etc. A linguagem Java tem uma Collections Framework sofisticada, que permite criar e gerenciar coleções de vários tipos de objetos. Esta seção não ensinará nada sobre o Java Collections, mas apresentará as classes de coleção mais usadas e ensinará a começar a usá-las.

Arrays

A maioria das linguagens de programação inclui o conceito de array para conter uma coleção de coisas, e a linguagem Java não é exceção. Um array é uma coleção de elementos do mesmo tipo.

Nota: os colchetes retos nos exemplos de código dessa seção fazem parte da sintaxe obrigatória do Java Collections, não dos indicadores de elementos opcionais.

Há duas formas de declarar um array:

  • Criá-lo com um determinado tamanho, que é fixo para toda a vida do array.
  • Criá-lo com um determinado conjunto de valores iniciais. O tamanho desse conjunto determina o tamanho do array — terá exatamente o tamanho suficiente para conter todos esses valores, e esse tamanho será fixo durante toda a vida do array.

Declarando um array

Em geral, o array é declarado desta forma:

newelementType [arraySize]

Há duas formas de criar um array de números inteiros. Esta instrução cria um array com espaço para cinco elementos, mas o array está vazio:

// creates an empty array of 5 elements:
int[] integers = new int[5];

Esta instrução cria e inicializa o array ao mesmo tempo:

// creates an array of 5 elements with values:
int[] integers = new int[] { 1, 2, 3, 4, 5 };

Os valores iniciais ficam entre chaves e são separados por vírgulas.

Arrays do jeito difícil

Uma forma mais difícil de criar um array seria criá-lo e, em seguida, codificar um loop para inicializá-lo:

int[] integers = new int[5];
for (int aa = 0; aa < integers.length; aa++) {
  integers[aa] = aa;
}

Esse código declara o array de números inteiros de cinco elementos. Se você tentar colocar mais do que cinco elementos no array, o Java Runtime não aceitará e lançará uma exceção. Você aprenderá sobre as exceções e a sua manipulação na Parte 2.

Carregando um array

Para carregar o array, você faz um loop pelos números inteiros, começando 1 e percorrendo todo o comprimento do array (que você obtém chamando .length no array — mais informações sobre isso em breve). Nesse caso, você para quando chega ao 5.

Uma vez carregado o array, é possível acessá-lo como antes:

Logger l = Logger.getLogger("Test");
for (int aa = 0; aa < integers.length; aa++) {
  l.info("This little integer's value is: " + integers[aa]);
}

Esta sintaxe (nova desde o JDK 5) também funciona:

Logger l = Logger.getLogger("Test");
for (int i : integers) {
  l.info("This little integer's value is: " + i);
}

Considero que a sintaxe mais nova é mais simples de trabalhar e usarei essa sintaxe ao longo desta seção.

O índice de elementos

O array é como uma série de depósitos — e cada depósito contém um elemento de um determinado tipo. O acesso a cada depósito é obtido por meio de um index:

element = arrayName [elementIndex];

Para acessar um elemento, você precisa da referência ao array (o nome dele) e do índice no qual o elemento que você quer reside.

O método length

Um dos métodos convenientes, como você já viu, é o length. É um método integrado — portanto, a sua sintaxe não inclui os parênteses de sempre. Basta digitar a palavra length e ele retorna — como era de se esperar — o tamanho do array.

Os arrays na linguagem Java são baseados em zero. Sendo assim, em um array chamado array, o primeiro elemento no array sempre reside em array[0], e o último reside em array[array.length - 1].

Um array de objetos

Você viu que os arrays podem conter tipos primitivos, mas vale ressaltar que eles também podem conter objetos. Nesse sentido, o array é a coleção mais proveitosa da linguagem Java.

A criação de um array de objetos java.lang.Integer não é muito diferente da criação de um array de tipos primitivos. Novamente, há duas formas de fazer isso:

// creates an empty array of 5 elements:
Integer[] integers = new Integer[5];
// creates an array of 5 elements with values:
Integer[] integers = new Integer[] { Integer.valueOf(1),
                                     Integer.valueOf(2)
                                     Integer.valueOf(3)
                                     Integer.valueOf(4)
                                     Integer.valueOf(5));

Encaixotando e desencaixotando

Todos os tipos primitivos da linguagem Java têm uma classe correspondente no JDK, como se pode ver na Tabela 4:

Tabela 4. Primitivas e correspondentes no JDK
PrimitivaCorrespondente no JDK
booleanjava.lang.Boolean
bytejava.lang.Byte
charjava.lang.Character
shortjava.lang.Short
intjava.lang.Integer
longjava.lang.Long
floatjava.lang.Float
doublejava.lang.Double

Cada classe do JDK fornece métodos para analisar e converter da sua representação interna para um tipo primitivo correspondente. Por exemplo: esse código converte o valor decimal 238 para um Integer:

int value = 238;
Integer boxedValue = Integer.valueOf(value);

Essa técnica é conhecida como encaixotamento, porque você coloca a primitiva em um wrapper (uma caixa).

De forma semelhante, para converter a representação de Integer para o seu correspondente int , você deve desencaixotá-lo , desta forma:

Integer boxedValue = Integer.valueOf(238);
int intValue = boxedValue.intValue();

Autoboxing e auto-unboxing

Em termos estritos, não é necessário encaixotar e desencaixotar as primitivas de forma explícita. Em vez disso, é possível usar os recursos de autoboxing e auto-unboxing da linguagem Java, da seguinte forma:

int intValue = 238;
Integer boxedValue = intValue;
//
intValue = boxedValue;

Entretanto, eu recomendo evitar o autoboxing e auto-unboxing, porque podem causar problemas no código. O código nos fragmentos de encaixotamento e desencaixotamento é mais óbvio — e, portanto, mais legível — que o código com autobox, e eu creio que o esforço a mais vale a pena.

Analisando e convertendo tipos encaixotados

Você viu como obter um tipo encaixotado; mas o que você faria para analisar um String que você suspeita que tenha um tipo encaixotado na sua caixa adequada? As classes do wrapper do JDK também têm métodos para isso:

String characterNumeric = "238";
Integer convertedValue = Integer.parseInt(characterNumeric);

Também é possível converter o conteúdo de um wrapper JDK para String:

Integer boxedValue = Integer.valueOf(238);
String characterNumeric = boxedValue.toString();

Observe que você usa o operador de concatenação em uma expressão String (você já viu isso em chamadas de Logger), o tipo primitivo sofre autoboxed e toString() é chamado automaticamente nos tipos primitivos. Muito conveniente.

Listas

Uma List é uma construção de coleção que é, por definição, uma coleção ordenada, também conhecida como sequência. Como a List é ordenada, você controla totalmente o local da List para o qual os itens vão. Uma coleção List de Java só pode conter objetos e define um contrato rigoroso em relação ao seu comportamento.

List é uma interface — portanto, não é possível instanciá-la diretamente. Você trabalhará com a sua implementação mais frequente, ArrayList:

List<Object> listOfObjects = new ArrayList<Object>();

Observe que designamos o objeto ArrayList a uma variável do tipo List. A programação Java permite designar uma variável de um tipo a outro, desde que a variável à qual está sendo designada seja uma superclasse ou interface implementada pela variável a partir da qual ela foi designada. Veremos mais detalhes sobre a designação de variáveis na Parte 2 , na seção Herança .

Tipo formal

E esse <Object> no fragmento de código acima? É conhecido como tipo formal e informa ao compilador que essa List contém uma coleção do tipo Object — isso significa que você pode colocar praticamente qualquer coisa na List.

Se você quisesse aumentar as restrições em relação ao que pode e não pode entrar na List, a definição seria diferente:

List<Person> listOfPersons = new ArrayList<Person>();

Agora a sua List só pode conter instâncias de Person .

Usando Lists

Usar Lists é muito fácil, como acontece nas coleções Java em geral. Estas são algumas coisas que podem ser feitas com Lists:

  • Colocar alguma coisa na List.
  • Perguntar à List qual é o seu tamanho atual.
  • Tirar coisas da List.

Vamos experimentar algumas dessas opções. Você já viu como criar uma instância de List instanciando o seu tipo de implementação ArrayList ; portanto, você começará daí.

Para colocar algo em uma List, chame o método add() :

List<Integer> listOfIntegers = new ArrayList<Integer>();
listOfIntegers.add(Integer.valueOf(238));

O método add() inclui o elemento no final da List.

Para perguntar à List qual é o tamanho dela, chame size():

List<Integer> listOfIntegers = new ArrayList<Integer>();
listOfIntegers.add(Integer.valueOf(238));
Logger l = Logger.getLogger("Test");
l.info("Current List size: " + listOfIntegers.size());

Para recuperar um item da List, chame get() e passe para ele o índice do item que você quer:

List<Integer> listOfIntegers = new ArrayList<Integer>();
listOfIntegers.add(Integer.valueOf(238));
Logger l = Logger.getLogger("Test");
l.info("Item at index 0 is: " listOfIntegers.get(0));

Em um aplicativo real, uma List conteria registros ou objetos de negócios e, possivelmente, você teria que examinar todos eles como parte do processamento. Como fazer isso de forma genérica? Você quer fazer uma iteração na coleção — e pode fazer isso porque List implementa a interface java.lang.Iterable . (Você aprenderá sobre as interfaces na Parte 2.)

Iterable

Se uma coleção implementa java.lang.Iterable, ela é chamada de coleção iterável. Isso significa que é possível começar em uma ponta e percorrer a coleção item por item até os itens acabarem.

Você já viu a sintaxe especial para fazer iteração em coleções que implementam a interface Iterable na seção Loops . Ela apareceu novamente:

for (objectType varName : collectionReference) {
  // Start using objectType (via varName) right away...
}

Fazendo iteração em uma List

O exemplo anterior foi abstrato; este é mais realista:

List<Integer> listOfIntegers = obtainSomehow();
Logger l = Logger.getLogger("Test");
for (Integer i : listOfIntegers) {
  l.info("Integer value is : " + i);
}

Aquele fragmento pequeno de código faz a mesma coisa que este, mais longo:

List<Integer> listOfIntegers = obtainSomehow();
Logger l = Logger.getLogger("Test");
for (int aa = 0; aa < listOfIntegers.size(); aa++) {
  Integer I = listOfIntegers.get(aa);
  l.info("Integer value is : " + i);
}

O primeiro fragmento usa uma sintaxe taquigráfica: não há variável index (aa , neste caso) para inicializar, nem chamada ao método get() de List .

Como Lista estende java.util.Collection, que implementa Iterable, é possível usar a sintaxe taquigráfica para fazer iteração em qualquer List.

Conjuntos

O Set é uma construção de coleções que, por definição, contém elementos exclusivos — ou seja, sem duplicatas. Embora uma List possa conter o mesmo objeto centenas de vezes, um Set só pode conter uma determinada instância uma vez. Uma coleçãoSet de Java só pode conter objetos e define um contrato rigoroso em relação ao seu comportamento.

Como Set é uma interface, não é possível instanciá-la diretamente — portanto, mostrarei uma das minhas implementações favoritas: HashSet. HashSet é fácil de usar e é semelhante à List.

Estas são algumas coisas que podem ser feitas com Set:

  • Colocar alguma coisa no Set.
  • Perguntar ao Set qual é o seu tamanho atual.
  • Tirar coisas do Set.

Usando Sets

O atributo diferencial do Set é a garantia de exclusividade entre os elementos, mas a ordem dos elementos não importa. Considere o código a seguir:

Set<Integer> setOfIntegers = new HashSet<Integer>();
setOfIntegers.add(Integer.valueOf(10));
setOfIntegers.add(Integer.valueOf(11));
setOfIntegers.add(Integer.valueOf(10));
for (Integer i : setOfIntegers) {
  l.info("Integer value is: " + i);
}

Você poderia esperar que o Set tivesse três elementos, mas na verdade ele só tem dois porque o objeto Integer que contém o valor 10 só será incluído uma vez.

Tenha em mente esse comportamento ao fazer iteração em um Set, da seguinte forma:

Set<Integer> setOfIntegers = new HashSet();
setOfIntegers.add(Integer.valueOf(10));
setOfIntegers.add(Integer.valueOf(20));
setOfIntegers.add(Integer.valueOf(30));
setOfIntegers.add(Integer.valueOf(40));
setOfIntegers.add(Integer.valueOf(50));
Logger l = Logger.getLogger("Test");
for (Integer i : setOfIntegers) {
  l.info("Integer value is : " + i);
}

É possível que os objetos sejam impressos em uma ordem diferente da ordem de inclusão, porque um Set garante a exclusividade, não a ordem. Você verá isso se colar o código acima no método main() da sua classe Person e executá-lo.

Mapas

Um Map é uma construção de coleção conveniente, porque permite associar um objeto(a chave) a outro (o valor). Como você pode imaginar, a chave de Map deve ser exclusiva e é usada para recuperar o valor posteriormente. Uma coleção Map de Java só pode conter objetos e define um contrato rigoroso em relação ao seu comportamento.

Como Map é uma interface, não é possível instanciá-la diretamente — portanto, mostrarei uma das minhas implementações favoritas: HashMap.

Estas são algumas coisas que podem ser feitas com Maps:

  • Colocar alguma coisa no Map.
  • Tirar coisas do Map.
  • Obter um Set de chaves do Map— para fazer iteração nele.

Usando Maps

Para colocar algo em um Map, é necessário ter um objeto que represente a sua chave e um objeto que represente o seu valor:

public Map<String, Integer> createMapOfIntegers() {
  Map<String, Integer> mapOfIntegers = new HashMap<String, Integer>();
  mapOfIntegers.put("1", Integer.valueOf(1));
  mapOfIntegers.put("2", Integer.valueOf(2));
  mapOfIntegers.put("3", Integer.valueOf(3));
  // . . .
  mapOfIntegers.put("168", Integer.valueOf(168));
}

Neste exemplo, Map contém Integers, chaveados por um String, que coincidentemente é a sua representação de String . Para recuperar um valor específico Integer , você precisa da sua representação de String :

mapOfIntegers = createMapOfIntegers();
Integer oneHundred68 = mapOfIntegers.get("168");

Usando Set com Map

Ocasionalmente, você pode ter uma referência a um Map e simplesmente quer percorrer todo o conjunto do seu conteúdo. Nesse caso, você precisa de um Set das chaves do Map:

Set<String> keys = mapOfIntegers.keySet();
Logger l = Logger.getLogger("Test");
for (String key : keys) {
  Integer value = mapOfIntegers.get(key);
  l.info("Value keyed by '" + key + "' is '" + value + "'");
}

Observe que o método toString() do Integer recuperado do Map é chamado automaticamente quando é usado na chamada de Logger . Map não retorna uma List das suas chaves porque o Map é chaveado e cada chave é exclusiva; a exclusividade é a característica diferencial de um Set.


Arquivando código Java

Agora que você aprendeu um pouco sobre a criação de aplicativos Java, talvez você esteja se perguntando como empacotá-los para que os outros desenvolvedores possam usá-los ou como importar código de outros desenvolvedores para os seus aplicativos. Esta seção mostra como fazer isso.

JARs

O JDK vem com uma ferramenta chamada JAR, que significa Java Archive. Essa ferramenta é usada para criar arquivos JAR. Depois de empacotar o seu código em um arquivo JAR, outros desenvolvedores podem simplesmente soltar o arquivo JAR nos projetos e configurar os projetos deles para usar o seu código.

Criar um arquivo JAR no Eclipse é fácil. Na sua área de trabalho, clique com o botão direito no pacote com.makotogroup.intro e selecione Export. Você verá o diálogo mostrado na Figura 8. Escolha Java > JAR file.

Figura 8. Caixa de diálogo Export.
Caixa de diálogo Export.

Quando a próxima caixa de diálogo abrir, navegue para o local onde você quer armazenar o seu arquivo JAR e dê ao arquivo o nome que quiser. A extensão .jar é o padrão, que eu recomendo usar. Clique em Finish.

Você verá o seu arquivo JAR no local que você selecionou. É possível usar as classes nele a partir do seu código se você o colocar no caminho de construção no Eclipse. Fazer isso também é fácil, como você verá a seguir.

Usando aplicativos de terceiros

Conforme você vai ficando mais à vontade com a criação de aplicativo Java, é conveniente usar cada vez mais aplicativos de terceiros para suportar o seu código. Para dar um exemplo, digamos que você queira usar joda-time, uma biblioteca de substituição do JDK para fazer tratamentos, manipulações e cálculos de data/hora.

Suponha que você já fez o download do joda-time, que está armazenado em um arquivo JAR. Para usar as classes, a primeira etapa é criar um diretório lib no projeto e soltar o arquivo JAR nele:

  1. Clique com o botão direito na pasta-raiz Intro, na visualização Project Explorer.
  2. Escolha New > Folder e dê o nome lib para a pasta.
  3. Clique em Finish.

A nova pasta aparece no mesmo nível de src. Agora copie o arquivo joda-time .jar para o seu novo diretório lib . Neste exemplo, o arquivo é chamado joda-time-1.6.jar. (Ao dar nomes para arquivos JAR, é comum incluir o número da versão.)

Agora você só precisa pedir para o Eclipse incluir as classes do arquivo joda-time-1.6.jar no seu projeto:

  1. Clique com o botão direito no projeto Intro na sua área de trabalho e, em seguida, selecione Properties.
  2. Na caixa de diálogo Properties, selecione a guia Libraries, como mostra a Figura 9:
    Figura 9. Properties > Java Build Path
    Properties > Java Build Path
  3. Clique no botão Add External JARs e, em seguida, navegue para o diretório lib do projeto, selecione o arquivo joda-time-1.6.jar e clique em OK.

Depois que o código (ou seja, os arquivos de classe) do arquivo JAR foi processado pelo Eclipse, os arquivos ficam disponíveis para referência (importação) a partir do código Java. No Project Explorer, observe que há uma nova pasta chamada Referenced Libraries, que contém o arquivo joda-time-1.6.jar.


Escrevendo um bom código Java

Você já tem um conhecimento suficiente de Java para escrever programas Java básicos — isso significa que a primeira metade do tutorial está prestes a terminar. Esta seção final mostra algumas boas práticas que ajudarão a escrever um código Java mais limpo e de manutenção mais fácil.

Mantenha as classes pequenas

Você criou algumas classes neste tutorial. Depois de gerar pares de getter/setter até mesmo para o pequeno número de atributos (para os padrões de uma classe Java concreta), a classe Person tem 150 linhas de código. É uma classe pequena. Não é raro ver classes com 50 ou 100 métodos e mil linhas de origem (ou mais). Em termos de métodos, a recomendação é manter somente os que sejam necessários. Se você precisa de vários métodos auxiliares que basicamente fazem a mesma coisa, mas tomam parâmetros diferentes (como o método printAudit() ), essa opção é adequada. Certifique-se de limitar a lista de métodos somente ao necessário — e nada mais do que isso.

Em geral, as classes representam alguma entidade conceitual no seu aplicativo, e o tamanho delas deve refletir somente a funcionalidade para fazer o que a entidade precisa fazer. Devem estar focadas para fazer de forma correta um pequeno número de coisas.

Seja cuidadoso ao dar nomes aos métodos

Em termos de nomes de métodos, o padrão revelador de intenções é adequado. Um exemplo simples facilita o entendimento desse padrão. Qual dos seguintes nomes de método é mais fácil de decifrar rapidamente?

  • a()
  • computeInterest()

A resposta deveria ser óbvia mas, por alguma razão, alguns programadores tendem a dar aos métodos (e variáveis) nomes pequenos e abreviados. Com certeza,um nome longo demais pode ser inconveniente, mas o nome não precisa ser longo para expressar o que o método faz. É possível que, seis meses depois de escrever uma grande quantidade de código, você não se lembre do que pretendia fazer com um método chamado a(), más é óbvio que um método chamado computeInterest() faça o cálculo de juros.

Mantenha os métodos pequenos

Assim como as classes, métodos pequenos são melhores — e pelas mesmas razões. Eu tento seguir o idioma de limitar o tamanho dos métodos a uma página , tendo como referência a minha tela. Isso facilita a manutenção das minhas classes de aplicativo.

Se um método ocupa mais de uma página, eu o refatoro. Refatorar significa alterar o design de um código já existente sem alterar os seus resultados. O Eclipse tem um ótimo conjunto de ferramentas de refatoração. Geralmente, um método longo contém subgrupos de funcionalidade amontoados. Tome essa funcionalidade e passe-a para outro método (dando a ele um nome adequado) e passe parâmetros conforme a necessidade.

Limite cada método a uma única tarefa. Eu constatei que um método que faz uma coisa corretamente, em geral, não ocupa mais do que aproximadamente 30 linhas de código.

Use comentários

Por favor, use comentários. As pessoas que vierem depois de você (ou até mesmo você, seis meses depois) agradecerão. Talvez você conheça o antigo ditado: um código bem-escrito documenta a si mesmo; então, quem precisa de comentários? Mostrarei dois motivos pelos quais essa ideia é falsa:

  • Grande parte dos códigos não é bem-escrita.
  • Provavelmente, o seu código não é tão bem-escrito quanto você pensa.

Então, comente o seu código. Ponto final.

Use um estilo consistente

O estilo de codificação é uma questão de preferência pessoal, mas eu gostaria de dar este conselho: use a sintaxe Java padrão em relação às chaves:

public static void main(String[] args) {
}

Não use este estilo:

public static void main(String[] args) 
{
}

Nem este:

public static void main(String[] args) 
  {
  }

Por quê? É o padrão; consequentemente, boa parte do código que você encontra (como um código que você não escreveu, mas pode ser pago para fazer manutenção) provavelmente será escrito dessa forma. Isso posto, o Eclipse permite que você defina os estilos de código e formate o seu código como quiser. O importante é definir um estilo e permanecer com ele.

Use a criação de log integrada

Antes de o Java 1.4 introduzir a criação de log integrada, a forma canônica de descobrir o que o seu programa estava fazendo era realizar uma chamada de sistema como esta:

public void someMethod() {
  // Do some stuff...
  // Now tell all about it
  System.out.println("Telling you all about it:");
  // Etc...
}

O recurso de criação de log da linguagem Java (consulte O seu primeiro objeto Java) é uma alternativa melhor. Eu nunca uso System.out.println() no meu código — e recomendo que você também não use.

Seguindo as pegadas de Fowler

O melhor livro do segmento de mercado (em minha opinião e na opinião de outras pessoas) é Refactoring: Improving the Design of Existing Code, de Martin Fowler et al. (consulte Recursos ). O livro chega a ser divertido. Fowler e os seus coautores falam de "cheiros de código" que pedem refatoração e explicam detalhadamente as várias técnicas para corrigi-los.

Em minha opinião, a refatoração e a capacidade de escrever um código que põe o teste em primeiro lugar são as qualificações mais importantes que os novos programadores devem aprender. Se todos fossem bons nesses dois aspectos, haveria uma revolução no segmento de mercado. Se você ficar bom nestes dois aspectos, você produzirá um código mais limpo e aplicativos mais funcionais que os dos seus colegas.


Conclusão da Parte 1

Neste tutorial, você aprendeu sobre a programação orientada a objetos, descobriu a sintaxe Java que permite criar objetos úteis e se familiarizou com um IDE que ajuda a controlar o ambiente de desenvolvimento. Você sabe criar e executar objetos Java que fazem várias coisas, inclusive coisas diferentes baseadas em entradas diversas. Você também sabe arquivar os seus aplicativos em JAR para que outros desenvolvedores os usem nos programas deles e conhece algumas boas práticas básicas de programação Java.

O que vem a seguir

Na segunda metade deste tutorial, você começará a aprender algumas construções mais avançadas de programação Java, embora a discussão geral ainda tenha um escopo introdutório. Os tópicos de programação Java abordados nesse tutorial são:

  • Herança e abstração
  • Interfaces
  • Classes aninhadas
  • Expressões regulares
  • Genéricos
  • Tipos Enum
  • E/S
  • Serialização

Leia "Introduction to Java programming, Part 2: Constructs for real-world applications."

Recursos

Aprender

Obter produtos e tecnologias

  • JDK 6: faça o download do JDK 6 da Sun (Oracle).
  • Eclipse: faça o download do IDE Eclipse para desenvolvedores em Java
  • Developer Kits IBM: a IBM fornece vários Developer Kits para usar nas plataformas mais conhecidas.

Discutir

  • Participe da comunidade My developerWorks. Entre em contato com outros usuários do developerWorks e explore os blogs, fóruns, grupos e wikis voltados para desenvolvedores.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java
ArticleID=658296
ArticleTitle=Introdução à Programação em Java, Parte 1: Fundamentos da linguagem Java
publish-date=05172011