sexta-feira, 28 de março de 2008

[14] Entendendo métodos - PARTE 1 DE 3

Os métodos são as ações de uma classe. Até agora criamos métodos apenas para exibir mensagens no Console, e utilizamos alguns métodos já prontos de outras classes, como o nextInt() da classe Scanner, por exemplo. Neste Post vamos aprender um pouco mais sobre as estruturas dos métodos e como realizar cálculos matemáticos simples dentro dos métodos.


Estrutura básica de declaração de um método


MODIFICADOR DE ACESSO TIPO DO RETORNO IDENTIFICADOR (PARÂMETROS)


Observe esta declaração do método imprimir():

public void imprimir(){
//seus comandos de impressão
}
public: é um dos quatro modificadores de acesso existentes na linguagem Java. Falaremos sobre modificadores de acesso em Posts posteriores.

void: é um tipo de retorno "vazio". Isto significa dizer que o método imprimir() não retornará nenhum valor. Entraremos em detalhes sobre os tipos de retorno adiante.

imprimir: identificador do método. É através do identificador que um método pode ser chamado. Por exemplo, para o método imprimir ser chamado teríamos o seguinte código deve ser chamado:

imprimir();

(): dentro dos parênteses devem ser informados quais parâmetros o método requer para que possa ser chamado. No caso do método imprimir(), nenhum parâmetro foi informado.


Tipos de retorno


Um método pode retornar valores tanto do tipo primitivo quanto valores do tipo referência. Além desses tipos, um método pode retornar um valor especial, que representa "vazio". Tal valor é representado pela palavra-chave void. Caso o tipo de retorno NÃO seja void, a palavra-chave return deve ser chamada. Esta palavra-chave encerra o método e retorna o valor desejado.

Embora um método possa conter mais de uma instrução return, apenas uma das instruções return será chamada (a primeira que o compilador encontrar, dependendo do fluxo de execução). Isso quer dizer que um método só retorna um valor a cada vez que ele é chamado.

Retornando void

Quando na declaração de um método está definido que ele retornará void, isso implica em dizer que tal método não retornará valor algum. Qualquer tentativa de retorno de valor causará um erro de compilação. Observe um exemplo válido de um método com tipo de retorno void:

public void imprimeNomes(){

System.out.println("Java");
System.out.println("Imediato");
System.out.println("Seu tutorial Java");

}

Caso alguma tentativa de retorno ocorra, o compilador acusará um erro. Observe este exemplo:

public void imprimeNomes(){

System.out.println("Java");
System.out.println("Imediato");
System.out.println("Seu tutorial Java");

//retorno
return 40;

}
O seguinte erro será acusado pelo compilador:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Void methods cannot return a value


Quando o tipo de retorno do método é void, a instrução return pode ser utilizada para finalizar o método, mas não para retornar um valor. Observe este exemplo:

public void imprimeNomes(){

System.out.println("Java");
System.out.println("Imediato");
System.out.println("Seu tutorial Java");
return;

}
Este código está livre de erros. Quando o compilador ler a instrução return, ele vai simplesmente finalizar o método. Nenhuma ação funcional ocorrerá. Porém, se você inserir neste método alguma instrução abaixo do return, o compilador lhe exibirá a seguinte mensagem:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Unreachable code

Isto quer dizer que há códigos no método que não podem ser alcançados. Isto ocorre porque o return finaliza o método, desde já não faria sentido para o compilador existir instruções que não serão alcançadas dentro do método.


Retornando Tipos Primitivos

Como visto no Post 11, os tipos primitivos são:
  • * char
  • * byte
  • * short
  • * int
  • * long
  • * float
  • * double
  • * boolean
Desde já um método pode retornar qualquer um desses tipos de acordo com sua finalidade. Observe este método que calcula a soma de 5 + 10:

public int somar(){

return 5 + 10;

}
Note que a soma 5+10 retorna um número inteiro: 15. Logo, não seria viável, por exemplo, definir void como tipo de retorno do método somar() . Isto causaria o seguinte erro de compilação:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Void methods cannot return a value


Observe agora o método a seguir. Ele retorna um valor do tipo boolean:

public boolean retornarVerdadeiro(){

return true;

}
Qualquer outro valor retornado no método retornarVerdadeiro() que não seja do tipo boolean causará um erro de compilação, como no exemplo abaixo:

public boolean retornarVerdadeiro(){

return 30606f;

}
O seguinte erro de compilação será acusado:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Type mismatch: cannot convert from float to boolean



Retornando Tipos de Referência

Vimos no Post 12 que variáveis do tipo referência referenciam objetos, e é justamente um objeto que um método deve retornar caso seu tipo de retorno seja um tipo referência. Porém, o tipo de retorno especificado na declaração do método deve ser o tipo exato do objeto que o método deve retornar (ou subclasses do tipo informado. Estudaremos este detalhe em Posts posteriores).

Dada uma classe Pessoa:

public class Pessoa{

//atributos
String nome;
String idade;

//métodos
public void imprimirNome(){
System.out.println("NOME: "+nome);
}

}

Vamos declarar em uma classe qualquer o seguinte método:

public Pessoa retornarPessoa(){

Pessoa p = new Pessoa();
p.nome = "ANDRÉ";
p.idade = 23;

return p;

}
Este método está declarado corretamente e compilará sem erros. Note que o tipo de retorno de retorno é Pessoa, classe que criamos anteriormente. Lembre-se, um tipo de referência é uma classe.

O seguinte método também é válido:

public String retornarString(){

return "Uma string qualquer";

}
String também é um tipo, e "Uma string qualquer" é um objeto do tipo String. Mas, por favor, não se aborreça com este detalhe agora, pois estudaremos este detalhe em Posts Posteriores. Você pode iniciar uma pesquisa sobre isto para adiantar seus estudos. O seguinte método apresenta um erro. Tente identificá-lo antes de ler o comentário sobre ele:

public Pessoa retornarPessoa(){

Pessoa p = new Pessoa();
p.nome = "Juliana";
p.idade = 27;

return Pessoa;

}

Se você apontou que o erro está no momento do retorno, você está correto(a). O tipo de retorno deve ser um OBJETO Pessoa, e não a CLASSE Pessoa. Neste caso deveríamos retornar o objeto p para satisfazer o tipo de retorno exigido no método.

Bem, encerramos por aqui a primeira parte do tópico Entendendo métodos.

Um abraço e até a próxima

quinta-feira, 6 de março de 2008

[13] Comentários em Java

Neste Post vamos aprender a como fazer comentários na linguagem Java. Um comentário nada mais é do que um trecho no seu código que será ignorado pelo compilador. Você pode escrever comentários com diversas finalidades, como:

* Explicar trecho(s) de código
* Ignorar uma determinada linha de código
* Ignorar um bloco de código
* Escrever cabeçalhos de classes
* entre outros


Comentário de linha (//)

O comentário de linha faz com que tudo a direita do símbolo "//" seja ignorado pelo compilador.
Por exemplo:


public static void main(String[] args) {
//System.out.println("Java imediato");

}


Este programa não imprimirá a frase "Java imediato", pois a linha de comando System.out.println("Java imediato"); está sendo ignorada pelo compilador.


Observe um outro exemplo:


public static void main(String[] args) {
System.out.println("Java"); //System.out.println("imediato");
}


A saída deste programa será:

Java



Também podemos utilizar o comentário simples para escrever curtas observações:

//classe Player
public class Player{

//atributos
int id;
String name;
String IP;

//métodos
public void conectar(){
//implementar este método
}

}

Comentário de bloco (/* */)

O comentário de bloco permite que mais de uma linha sejam comentadas de uma só vez. Para isto abrimos o comentário de bloco com o símbolo "/*" e definimos o fim do comentário usando o símbolo "*/". Observe este exemplo de uso de comentário composto:
/* Classe Player Esta classe tem a finalidade de permitir que um jogador se conecte a um determinado servidor */
public class Player{

//atributos
int id;
String name;
String IP;


//métodos /* Este método ainda será implementado. */
public void conectar(){
//implementar este método
}

}


Como você deve ter percebido, não há problemas em haver mais de um tipo de comentário em uma classe.

Bem, neste Post encerramos por aqui. Um abraço e até a próxima

[12] Tipos de variáveis: tipos de referência



Os tipos de referência se diferem dos tipos primitivos porque os tipos primitivos armazenam valores, e os tipos de referência referenciam objetos. A declaração de uma variável local ou atributo de tipo de referência é semelhante ao de um tipo primitivo. Observe:

TIPO
nomeDaVariavel;




Aos poucos vamos migrando nosso vocabulário, desde já daqui por diante vamos nos adaptar a outra palavra: identificador. Em vez de "nome de um atributo" ou "nome de uma classe", de agora em diante chamaremos "identificador de um atributo" e "identificador de uma classe".









Porém, em vez de o tipo ser algo como int, float ou char, por exemplo, será uma classe - em Posts posteriores veremos que tipos de referência pode referenciar algo mais além do que uma classe comum.
Observe esta linha de código:

Scanner entrada;

No Post 9 nós tinhamos então uma variável de referência do tipo Scanner. Scanner é uma classe e "entrada" é o identificador da variável.
Neste caso, significa dizer que "entrada" está pronto para referenciar um objeto do tipo Scanner, porém até agora não o faz. Caso não se lembre, para começarmos a utilizar um objeto do tipo Scanner codificamos o comando:

Scanner entrada = new Scanner(System.in);

Esta linha faz com que "entrada" referencie um objeto do tipo Scanner. Um objeto Scanner, assim como qualquer outro objeto, é criado efetivamente quando usamos a palavra-chave new seguida do construtor do tipo do objeto - aprenderemos sobre construtores em Posts posteriores.
Logo, podemos imaginar que a nossa linha de comando resultou no seguinte esquema:Vejamos este trecho de código:
  1. Scanner e1;
  2. e1 = new Scanner(System.in);
  3. e1 = new Scanner(System.in);
A representação gráfica deste código resultaria em algo como:

Uma variável de referência referencia apenas 1 único objeto por vez, assim como as variáveis de tipos primitivos referenciam apenas 1 valor por vez. No caso da figura anterior, o primeiro objeto Scanner criado era referenciado pela variável "e1", ou seja, a única maneira de se acessar o primeiro objeto Scanner seria através da variável "e1". Como "e1" só pode referenciar um objeto Scanner por vez e na linha 3 ele passa a referenciar outro objeto, logo o primeiro objeto Scanner é perdido na memória e estará disponível para ser coletado pelo Garbage Collector - ou GC - da JVM.
Também é possível que mais de uma variável de referência referencie um mesmo objeto. Vamos antes criar uma classe Pessoa e exemplificar como um único objeto pode ser acessado por várias variáveis de referência:
public class Pessoa{
String nome;
int idade;

float peso;

float altura;


public static void main(String[] args){

Pessoa p1 = new Pessoa();
Pessoa p2 = p1;
Pessoa p3 = p2;

}



}
Quando o arquivo Pessoa.java for executado, o esquema gráfico do nosso código ficará da seguinte maneira:


Lembre-se, variáveis de referência armazenam simplesmente "referências a objetos", ou seja, se uma variável de referência referencia outra, então ambas referenciarão o mesmo objeto ou null.


Referência null

Quando não queremos que uma variável de referência referencie um objeto, podemos fazer com que ela referencie null.

null é uma palavra-chave para fazer com que uma variável de referência não referencie nenhum objeto.

Observe o exemplo:

Pessoa pes = new Pessoa();

pes = null;
Resultado:

Variáveis de referência locais

Todos os exemplos de variáveis de referências citados anteriormente são declarados e imediatamente inicializados. Toda variável declarada precisa referenciar algo caso seja utilizada. No caso das variáveis de referências, deve referenciar ou o valor null ou um objeto. Por exemplo:

public void metodoQualquer(){

Pessoa p;

}

Será compilado sem erros. Contudo, por enquanto, a variável "p" está inutilizada. Observe o exemplo a seguir:

public void metodoQualquer(){

Pessoa p;
p.nome = "Pollyana";

}


A variável "p" está sendo utilizada. Por estar sendo utilizada sem referenciar algum valor, o compilador acusará o seguinte erro:

The local variable p may not have been initialized

O próximo exemplo não possui erros de compilação:

public void metodoQualquer(){

Pessoa p = null;
p.nome = "Pollyana";

}


As variáveis de referência que são atributos de uma classe são inicializadas automaticamente com null, caso você as programar para receberem um objeto. Aprenderemos sobre inicialização de atributos em Posts posteriores.

NullPointerException

Se você ainda se deparou com esta exceção, sua hora chegará. Uma exceção NullPointerException ocorrerá quando você tentar acessar um objeto que não existe - frequentemente fazemos isso porque pensamos que tal objeto existe. Em IDEs como Eclipse, por exemplo, ao pressionar Ctrl+Espaço após o operador ponto"." de uma variável, automaticamente se abrirá uma caixa de seleção com atributos e métodos pertencentes ao tipo da classe em questão, como na imagem abaixo:



Isto muita vezes nos induz a acessar métodos, por exemplo, de objetos que não existem. Por exemplo:

  1. Pessoa p;
  2. p.nome = "André";

Seria como se na linha 1, você dissesse ao compilador: "Compilador, estou declarando uma variável do tipo Pessoa, e ela se chamará p", e na linha 2 você dissesse: "Compilador, quero que o atributo "nome" do objeto que minha variável p referencia tenha seu valor alterado para "André" ".

Logo, se este trecho de código for executado, uma exceção NullPointerException será lançada:


java.lang.NullPointerException


O seguinte trecho também gera exceção de NullPointerException:


Scanner entrada = new Scanner(System.in); Scanner entrada2 = entrada; entrada = null;
entrada.nextInt();

A variável "entrada" referenciava um objeto, logo em seguida a variável "entrada2" passou a referenciar o objeto de "entrada". Na linha 3, "entrada" passou a ter referência para null, e finalmente na linha 4 tentou-se acessar o método nextInt() através da variável de referência "entrada", que não mais referencia qualquer objeto.
Analisemos o nome da exceção: NullPointerException. Sua tradução significa algo como: "Exceção de ponteiro nulo". Isto significa dizer que tentou-se acessar algo de uma referência de objeto que não existe.

Bem, ficamos por aqui. Mais um abraço e bons estudos!