Wrappers em Java: Aprenda como utilizar
Veja neste artigo como funcionam, o que são e como utilizar os Wrappers em Java.
Se você já trabalhou com Java, mesmo que por pouco tempo já deve ter trabalhado alguma vez com Wrappers e nem percebeu. Este artigo tem como principal objetivo mostrar a importância dos Wrappers e principalmente o que eles são.
Wrappers vem do verbo inglês “wrap” que significa envolver. Eles são um nome adicional ao padrão de projeto Decorator. Tem como principal função “envolver coisas” adicionando funcionalidades à ela.
O Java conta com diversos Wrappers que adicionam funcionalidades a outras classes ou tipos primitivos, um exemplo dele é o Integer, que é o Wrapper do tipo primitivo int. Que tipo de funcionalidade você pode executar tendo apenas uma variável definida como “int”? Nenhuma, a não ser atribuir valores, pois int é um tipo primitivo e não possuí métodos.
O Java possui oito wrappers para tipos primitivos que adicionam
a funcionalidade de tratar tipos primitivos como classes. Quando você faz um:
Integer i = Integer.valueOf(2);
Você está criando uma classe, que "envolve" o número 2 (primitivo) e
adiciona métodos como intValue() nele. Você ainda ganha a funcionalidade de
trabalhar com o número 2 como se ele fosse um objeto. O Java (a partir da
versão 5) é inteligente o suficiente para criar ou desfazer wrappers de tipo
primitivo automaticamente (Autoboxing), de tão útil e comum que é essa prática,
veremos mais a diante como funciona o Autoboxing.
Existem dezenas de wrappers: para tratar o fluxo de conexões como orientado a objetos (ObjectInputStream), fluxos de audio (AudioInputStream), baseados em tipos primitivos (DataInputStream), ou adicionar buffers (BufferedInputStream) a eles. Todos esses são exemplos de wrappers para o básico e sem funcionalidade InputStream. E o interessante, é que, esses wrappers podem ser combinados (pode-se fazer um FileInputStream, associa-lo a um BufferedInputStream e ler dados primitivos dele após associar o resultado a um DataInputStream).
Com o Wrapper Integer envolvendo o tipo primitivo int você consegue executar métodos como é o caso do: parseInt, valueOf e assim por diante.
Na Figura 1você confere uma lista de Wrappers muito comuns no Java.
Figura 1. Wrappers de Tipos primitivos
Então se temos Wrappers porque usar os tipos primitivos? Simples, eles são mais rápidos e consomem menos memória, afinal não tem implementação de métodos ou qualquer outro algoritmo complexo que venha a consumir mais tempo da JVM.
Fique atento ao tentar realizar conversões de para Wrappers do tipo errado, pois você verá exceções como “NumberFormatException”, como por exemplo a tentativa de converter o literal “dois” para um tipo “Integer”. A atenção deve ser dobrada pois não há erro em tempo de compilação, ou seja, seu código não mostrará nenhum erro de sintaxe, mas quando esta linha de código for executada você verá a exceção apontada acima. Veja o exemplo da Listagem 1.
Listagem 1. Convertendo de forma errada
public class ExceWrap {
public static void main(String[] args) {
int z= Integer.parseInt("dois");
System.out.println(z);
/* codigo compila sem problemas mais uma excecao vai acontecer
* nao há nada de errado na sintaxe
* porem a jvm nao consegue converter uma string literal
* em um numero inteiro
*/
}}
Exception in thread "main" java.lang.NumberFormatException: For input string: "dois"
//Por outro lado, a classe abaixo irá compilar e executar normalmente
public class Par {
public static void main(String[] args) {
//String - primitivo
double d = Double.parseDouble("10");
System.out.println(d);
}}
//A classe abaixo também apresentará erro
public class NoValue {
public static void main(String[] args) {
Long l = new Long(8);
int lh = l.longValue();
/* nao compila o to tentando colocar um long
* dentro de um int nao é valido isso
*/
}}
//Esta funcionará normalmente
public class OfVal {
public static void main(String[] args) {
//String --> OBJETOS
Float f = Float.valueOf("10");
System.out.println(f);
Integer i = new Integer(10);
//Objeto --> Primitivo
int g = i.intValue();
}}
//Veja um exemplo de teste de referência
public class WrpObjt {
public static void main(String[] args) {
Integer g = new Integer (10);
Integer h = new Integer(10);
System.out.println(g==h);//false
/* aqui dois objetos diferentes
* porem com mesmo valor
* == testa a referencia e nao valores dos
* objetos */}}
Atente também que tipos primitivos não podem ser utilizados em Collections, só objetos. Sendo assim, a solução é usar Wrappers. E já que estamos no assunto de Wrappers, não poderíamos falar da novidade trazida pelo Java 5, o Autoboxing que será explicado na próxima seção.
Autoboxing com Wrappers
Você já deve ter se imagine que como Wrapper é um Objeto você deve sempre passar um tipo primitivo para criar um Wrapper especifico daquele tipo primitivo, algo como mostrado na Listagem 2.
Listagem 2. Criando um Wrapper
Integer soma = new Integer(10);
Ótimo, e se quisermos criar um Hashmap teríamos que fazer algo como mostrado na Listagem 3.
Listagem 3. Criando uma lista sem Autoboxing
HashMap hashMap = new HashMap();
hashMap.put(new Integer(10), “Carlos”);
hashMap.put(new Integer(11), “Jose”);
hashMap.put(new Integer(12), “Pedro”);
Após o Java 5 surgiu a funcionalidade do Autoboxing onde o próprio Java já converte o tipo primitivo em Wrapper se este achar que é necessário. Veja a Listagem 4 com Autoboxing funcionando.
Listagem 4. Criando uma lista com Autoboxing
HashMap hashMap = new HashMap();
hashMap.put(10, “Carlos”);
hashMap.put(11, “Jose”);
hashMap.put(12, “Pedro”);
Boxing Conversion
O Boxing é a conversão de tipos primitivos em seu respectivo Wrapper correspondente, ou seja, veja o exemplo na Listagem 5.
Listagem 5. Boxing Conversion
Boolean meuBoolean = true;
//a conversão é feita de forma automática para o boolean
Integer meuInteger = 1203;
Double meuDouble = 10.20;
É óbvio que se você tentar realizar um Boxing Conversion de um tipo primitivo para um Wrapper errado você terá um erro de compilação.
Unboxing Conversion
O Unboxing Conversion é quando você deseja fazer o inverso feito na seção 2.1, ou seja, deseja converter um objeto para um tipo primitivo. Veja os exemplos na Listagem 6.
Listagem 6. Exemplos de Unboxing Conversion
boolean a = new Boolean(“True”);
char c = new Character(‘c’);
byte b = new Byte(“1”);
float f = new Float(1.0f);
Comparando Wrappers
Possivelmente você já deve ter comparado Strings em Java, e deve saber que utilizar o operador “==” não funciona, é por isso que a implementação no método equals nos “Pojos” são muito importantes. Com os Wrappers você também deve utilizar o método equals para realizar estes tipos de comparações, não esqueça que Wrappers são objetos e não tipos primitivos.
Veja na Listagem 7 uma comparação certa e outra errada.
Listagem 7. Comparando Wrappers da forma certa e da forma errada
Integer a = 200;
Integer b = 200;
a.equals(b); // Retorna TRUE
a == b; // Retorna FALSE
A diferença entre o equals e o operador ==, é que no operador == ele compara a referência do objeto, afinal você está literalmente “comparando” os objetos e mesmo que estes fossem idênticos (em todos os atributos) eles ocupam locais diferentes na memória e possuem identificação diferente na JVM, resumindo não são iguais. Utilizando o equals você compara o valor deles, igual como se tivesse comparando dois tipos primitivos.
O Problema encontrado
Quando falamos que você não deve utilizar o == para comparar Wrappers, é porque não deve mesmo e continuamos afirmando isso. Ainda afirmamos que quando você realizar esse tipo de comparação receberá FALSE, visto que ele compara a referência em memória do objeto. O problema é que se você fizer o teste da Listagem 8 verá que ele retornará verdadeiro.
Listagem 8. Comparando Wrappers com o operador ==
Integer x = 120;
Integer y = 120;
x==y; //Retorna TRUE
Porque então o exemplo da Listagem 8 retorna TRUE? Por causa do padrão de projeto Flyweigth. Ele tenta reduzir o consumo de memória mudando a referência dos objetos que são idênticos, ou seja, os objetos x e y apontam para um mesmo objeto com que tem as características ditando que o valor é 120, assim quando compararmos com ==, já que estamos comparando a referência do objeto e ela é a mesma com o Flyweigth o resultado será TRUE. Isso por padrão só é aplicado nos valores de -128 até 127, mas na dúvida use sempre o equals.
Possivelmente, como citamos no inicio do artigo, você já deve ter usado Wrapper em algum momento, mas nunca soube de fato o que era, na verdade isso acaba sendo tão automático que muitas das vezes você deve ter usado o Integer, Float ou Boolean Wrapper pensado que é um tipo primitivo, quando na verdade você está envolvido pela Orientação à Objetos.
A importância deste nem precisa ser descrita, já que são utilizados com freqüência e fazem a maior parte do trabalho quando precisamos. Além disso, existem mais Wrappers do que apenas de tipos primitivos, faça uma pesquisa sobre estes e encontrará um mundo de novos conceitos e aprendizados.
Wrappers não são utilizados apenas com tipos primitivos, pelo seu conceito de “envolver coisas”, podemos utilizá-los em objetos, por exemplo: Imagine que você quer adicionar mais funcionalidades a um Jbutton padrão, então você poderia criar um Wrapper chamado WrapperJButton que conteria o Jbutton e mais vários método que você acha necessário para sua aplicação.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo