Pular para o conteúdo principal

Analisando na Prática o uso de Primitivos e Wrappers

O uso de tipos primitivos e Wrappers é um tema que traz diversas discussões, inclusive existem vários tutorias que mostram a aplicabilidade de cada uma das estratégias em diferentes cenários.

As Classes Wrappers


As classes Wrappers são aquelas que representam os tipos primitivos da linguagem Java, há algum tempo existiam autores que falavam que Java não era uma linguagem 100% OO por tratar os tipos básicos como primitivos, mas isso acabou quando adicionaram os tipos Wrappers a linguagem.

O Wrappers são classes imutáveis, e possuem vários métodos utilitários que facilitam conversões, parses, formatação, entre outras funcionalidades bem utilizadas no dia a dia.

Vamos analisar cada tipo primitivo e sua representação em classe Wrapper:
  • byte
    • Byte;
  • short
    • Short;
  • int
    • Integer;
  • long
    • Long;
  • boolean
    • Boolean;
  • char
    • Character;
  • float
    • Float;
  • double
    • Double;

Comparação entre Wrappers


Vamos entender como esses objetos funcionam no quesito comparação, já analisei casos onde uma comparação de valores iguais não resultavam em true, vamos analisar alguns motivos para isso ocorrer:

 Integer oneWrapper = 1; //Autoboxing do valor <1> para a variavel oneWrapper
 Integer twoWrapper = 1; //Autoboxing do valor <1> para a variavel twoWrapper
  
 System.out.println(" Comparação de Wrappers \n");
 System.out.println(oneWrapper == twoWrapper);
 System.out.println(oneWrapper != twoWrapper);
 System.out.println(oneWrapper.equals(twoWrapper));

O Resultado do nosso código será o seguinte:
oneWrapper == twoWrapper : true
oneWrapper != twoWrapper : false
oneWrapper.equals(twoWrapper) : true

Para entender os resultado, vamos lembrar que quando criamos as variáveis do tipo Wrapper realizando a atribuição direta de um valor, o compilador realiza o autoboxing, que é a conversão de um tipo primitivo em tipo Wrapper.

Na primeira condição temos oneWrapper == twoWrapper, quando comparamos objetos com == a comparação acontece entre as referências dos objetos, e neste caso como as variáveis foram criadas através de atribuição direta, o valor 1 será reaproveitado do pool de objetos, assim as variáveis apontaram para o mesmo objeto em memória.

Na segunda condição temos oneWrapper != twoWrapper, aqui a explicação é a mesma da primeira.

Na terceira condição temos oneWrapper.equals(twoWrapper), quando aprendemos manipulação de objetos com Java, analisamos o método equals(), que é o método que utilizamos para analisar se um objeto é igual ao outrolembrando que os Wrappers são objetos, portanto o equals é a melhor forma de realizar a comparação.


Integer oneWrapper = 1; //Autoboxing do valor <1> para a variavel oneWrapper
Integer twoWrapper = new Integer(1); //Criação sem reaproveitar o objeto do pool
  
System.out.println(" Comparação de Wrappers com Instância direta \n");
System.out.println(oneWrapper == twoWrapper);
System.out.println(oneWrapper != twoWrapper);
System.out.println(oneWrapper.equals(twoWrapper));

O resultado será o seguinte:

oneWrapper == twoWrapper        : false
oneWrapper != twoWrapper         : true
oneWrapper.equals(twoWrapper) : true

Vamos entender o resultado, no primeiro exemplo é feita uma comparação entre 2 Wrappers utilizando o operador ==, mas os objetos foram criados de forma diferente, na variável oneWrapper foi realizado a atribuição do valor diretamente onde irá ser realizado o autoboxing, já a variável twoWrapper foi criada utilizando o construtor de Integer.

Ao criar utilizando o construtor, não reaproveitamos objetos do pool de objetos, ou seja, foi criado outro objeto em memória, e como já sabemos o operador == realiza a comparação entre referências, portanto resultado da comparação é false.

No segundo exemplo utilizando o operador != aqui o conceito é o mesmo do exemplo anterior, o valor de ambas as variáveis é 1, mas lembrando que o operador irá comparar referências que são diferentes portanto o resultado é true.

Já no terceiro exemplo utilizamos o método equals() para realizar a comparação, neste caso o que será avaliado é o valor das variáveis, portanto o resultado é true.

Analisando a Performance


Um ponto importante é analisarmos a performance das operações de boxing dentro de estruturas de repetição, estas operações são custosas pois exigem  muitas transformação em laços.

Vamos analisar alguns códigos para entendermos os casos.

long init = System.currentTimeMillis();
  
long result = 0;
  
for (long i = 0; i < 1000000000; i++) {
     result += i;
}
  
long end = System.currentTimeMillis();
  
System.out.println(" Tempo: "+(end - init)); 

O Resultado da execução é:  Tempo: 460

Esse é um código onde apenas executamos um soma entre as variáveis result e i utilizando o operador += , perceba que como estamos usando o tipo long a soma acontece sem maiores problemas.


long init = System.currentTimeMillis();
  
Long result = 0L;
  
for (long i = 0; i < 1000000000; i++) {
     result += i;
}
  
long end = System.currentTimeMillis();
  
System.out.println(" Tempo: "+(end - init));

O Resultado da execução é:  Tempo: 5043

Este exemplo é quase igual ao anterior, a unica diferença que a variável result agora é do tipo Wrapper Long e não long primitiva, após a execução notamos um tempo superior ao do primeiro exemplo.

Acontece que o operador += só pode ser usado em operações de tipos primitivos, e em nosso exemplo a variável result é uma Wrapper, e neste caso a JVM é obrigada a realizar a operação de Autoboxing, deixando o laço mais lento.

Conclusão


O uso de Wrapper e Primitivos deve ser analisado em cada cenário, levando em consideração as operações que serão executadas, performance, cálculos, entre outros fatores.

Os recursos de Autoboxing e Unboxing são muito bons e deixaram a criação e manipulação de objetos mais produtiva, mas sempre devemos nos atentar para não utilizar em lugares onde poderemos ter problemas de performance.

Até mais.

Código Fonte

Referências


Comentários

Postagens mais visitadas deste blog

Utilizando LocalDate, LocalDateTime e LocalTime na Prática

Tudo bem pessoal, hoje iremos avaliar e analisar operações de manipulação de Datas envolvendo a JavaTime API introduzida no Java 8.

Exemplos da java.time API
Já se passaram alguns anos desde o lançamento do Java 8 e mesmo após este período, há empresas que desconhecem o poder da java.time API, esta foi uma nova API de datas introduzida no Java 8 visando resolver problemas que tínhamos com as velhas classes Date e Calendar.

Vamos mostrar vários exemplos práticos do uso da API:
Criação de objetos No exemplo abaixo, estamos criando os objetos para manipulação de datas, perceba que temos 3 tipos, sendo LocalDate para manipular datas, LocalDateTime para manipular data/hora e LocalTime para horas:
LocalDate localDate = LocalDate.now(); LocalDateTime localDateTime = LocalDateTime.now(); LocalTime localTime = LocalTime.now();
Utilizando formatação Aqui realizamos a operação de formatação, perceba que não foi necessário utilizar a classe SimpleDateFormat, que usaríamos em conjunto com D…

Lendo e Manipulando arquivos CSV com Java

Olá hoje veremos como realizar a leitura e manipulação de arquivos CSV com Java, mostrando que as novas versões da plataforma Java deixaram algumas tarefas simples de serem realizadas.

Exemplo de Arquivo Hoje em dia é comum ao realizar integrações ou carga de dados o uso de arquivos CSV, isto porque, este arquivo possui uma estrutura de fácil entendimento e simples de manipular na maioria das plataformas de desenvolvimento.

Para realizar a leitura dos dados vamos manipular um arquivo com as seguintes colunas: namecpfagephone address:

name;cpf;age;phone;address caio;123456789;20;1145223643;AvenidaPaulista vinicius;147852369;18;1125253625;AvenidaManoel sandra;963258741;30;1174587858;RuaTeixeira regina;125478522;40;1145254536;RuaFernando fernando;785245563;42;1145253669;RuaPereira augusto;456123014;50;1125363633;AvenidaPaulinia maria;456123789;10;1125455525;AvenidaNossaSenhora
Para representar os dados em objetos Java iremos utilizar a seguinte classe:

importlombok.AllArgsConstruc…

Versionamento de Banco Dados com Flyway

Olá pessoal, hoje iremos analisar e aprender como realizar o versionamento e gerenciamento das bases de dados relacionais utilizando o framework Flyway.

Versionamento de Banco Dados Ao trabalhar com desenvolvimento de sistemas é comum realizarmos o versionamento, isso porque uma aplicação pode necessitar de correções, novas funcionalidades e evoluções, onde para garantir a compatibilidade e cuidar do seu ciclo de vida, geramos versões onde é especificado quais itens estão presentes em cada release.
Vamos imaginar seguinte cenário: Sistema ERP1.0.0: Entrega dos módulos Financeiro e RH;1.1.0: Entrega do módulo Contas a Receber. Perceba que a ideia é controlar o que cada versão possui de diferente, e para controlar essas mudanças no lado da aplicação existem várias técnicas e ferramentas, mas e para controlar as mudanças no lado do Banco de dados ? 
Para isso podemos utilizar ferramentas de versionamento que ajudam a realizar este controle, a ferramenta que iremos utilizar é o Flyway.
Con…