Effective Java – Item 10 – Sobrescrever o método Equals (parte 1)

Por vezes é melhor herdar o método equals da classe Object do que sobrescrevê-lo.

Para que funcione de forma correta, o equals deve obedecer a um contrato geral, que define que ele seja:

• Reflexivo: x != null => x.equals(x) == true;
• Simétrico: x != null & y != null => x.equals(y) == true <=> y.equals(x) == true ;
• Transitivo: x != null & y != null & z != null => x.equals(y) == true & y.equals(z) == true & x.equals(z) == true;
• Consistente: x != null & y != null => x.equals(y) == true (|| false), quantas vezes for chamada.
• e quando nulo, x != null => x.equals(null) == false.

O primeiro item diz que um objeto deve ser igual a ele mesmo. Num Set, por exemplo, se essa propriedade não estiver presente, um objeto pode ser inserido duas vezes ou não removido corretamente.

Parece lógico mas o desenvolvedor pode cair em armadilhas. Vejamos como não obedecer a segunda propriedade, que diz que dois objetos devem acordar sobre a forma com eles são iguais.

// Broken - violates symmetry!
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
this.s = Objects.requireNonNull(s);
}
// Broken - violates symmetry!
@Override public boolean equals(Object o) {
if (o instanceof CaseInsensitiveString)
return s.equalsIgnoreCase(
((CaseInsensitiveString) o).s);
if (o instanceof String) // One-way interoperability!
return s.equalsIgnoreCase((String) o);
return false;
}
… // Remainder omitted
}

Ao comparar essas duas strings, a segunda propriedade será violada.

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";

Ao comparar cis.equals(s) será retornado true já que ele foi construído para desconsiderar o “case”. O problema ocorre quando s.equals(cis), que retorna false, já que não ignora o “case”. Um “claro caso de violação da simetria”.

Para corrigir, o método equals deve ficar da seguinte forma.

@Override public boolean equals(Object o) {
return o instanceof CaseInsensitiveString &&
((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}

Esqueça a tentativa de lidar com String, o que é chamado no livro de “One-way interoperability!“.

Nesse post falei da primeira e segunda propriedade, sem as quais podem ocorrer inconsistências e causar exceções.

Então até o próximo, no qual continuarei com as outras propriedades.

PS.: a especificação do método equals é encontrada em https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object).

PS.2: nada é trivial.

Effective Java – Item 7 – Elimine referências obsoletas a objetos

Gerenciamento de memória em linguagens com Java, que possuem mecanismo de coleta de lixo, ou garbage collection mechanism, podem evitar problemas de perda de memória, ou “memory leaks“.

As “Memory Leaks” ocorrem quando objetos que já não são utilizados ainda ocupam espaço na memória. Esses objetos estão no Heap e suas variáveis na Stack, no caso do Java.

Não é por haver um mecanismo de coleta de lixo que o programador não deva se preocupar com problemas de memória que um código, até mesmo um simples, pode causar.

Perdas de memória podem gerar uma OutOfMemoryError mas o maior problema é que, na maioria da vezes, ela ocorre de forma silienciosa. E apenas podem ser descobertas com uma inspeção minuciosa do código e com o auxílio de ferramentas de debugging, conhecidas como “heap profiler“.

A classe abaixo armazena um array de objetos, permite o push e o pop de elementos e a cada push, dobra de tamanho.

// Can you spot the "memory leak"?
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}

O problema dela é no método pop. Quando um objeto é retornado e o tamanho diminuído, a stack ainda mantém uma referência obsoleta a esse objeto. Nessa caso, toda referência que estiver fora da “porção ativa” do array serão obsoletos. A porção ativa equivale aos elementos que o índice for menor que o tamanho do array.

Perda de memórias em linguagens como o Java são também conhecidas como retenção não intencionais de objetos, ou “unintentional object retentions“. Esses objetos ficam excluídos do coleta de lixo assim como objetos que ele possa referênciar, e assim por diante.

E a solução? Tornar nulas as referências assim que um objeto se tornar obsoleto. Segue o treco do código com a solução.

public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}

Mas cuidado. Tornar nula referências a objetos deve ser exceção e não regra. E a melhor maneira de eliminar referências obsoletas é definar cada variável num menor escopo possível.

Então quando se deve usar o “null out”? Quais aspectos tornam uma classe suscetível a “memory leaks”? De maneira simples, sempre que houver uma espécie de memória e que seja gerida por ela. No caso da classe Stack, é o array de elementos e seus métodos para incluir e remover. O garbage collector não tem como saber se um elemento está inválido, uma vez que guarda a referência aos objetos e não eles em si. Portanto, isso deve ser feito manualmente pelo programador.

Até o próximo item.

Effective Java – Item 6

Avoid creating unnecessary objects (evite criar objetos desnecessários)

O item do livro diz que é mais apropriado reusar objetos ao invés de criar novos objetos funcionalmente equivalentes cada vez que for necessário. Um objeto pode sempre ser reutilizado se for imutável.

O primeiro exemplo dado é a crição de uma String.

String s = new String("bikini"); // DON'T DO THIS!

Esse código cria uma instância cada vez que é executado e nenhum deles é necessário. O argumento do construtor (“bikini”) já é uma String.

O correto é String s = "bikini";

Em um loop, nesse caso, apenas uma única instância é criado, ao invés de uma para cada vez que for executado.

E se na mesma VM outro objeto contendo “bikini” reusará a instância já criada.

O código abaixo, que verifica se uma String é um numeral romano, e da forma como foi escrito, criará sempre um Pattern para expressão regular, o que é muito caro para a VM.

// Performance can be greatly improved!
static boolean isRomanNumeral(String s) {
return s.matches("^(?=.)M*(C[MD]|D?C{0,3})"
+ "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}

O certo seria criar um objeto imutável que seria reutilizado nas chamadas ao método.

// Reusing expensive object for improved performance
public class RomanNumerals {
private static final Pattern ROMAN = Pattern.compile(
"^(?=.)M*(C[MD]|D?C{0,3})"
+ "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
static boolean isRomanNumeral(String s) {
return ROMAN.matcher(s).matches();
}
}

 Esse código acima rodou 6.5 vezes mais rápido.

Um outro exemplo, que pode levar ao aumento de utilização de recursos, é utilizar o autoboxing, isto é, poder utilizar juntos primitivos e objetos que os encapsulam. Exemplo de long, primitivo, e Long, objeto.

// Hideously slow! Can you spot the object creation?
private static long sum() {
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}

O código acima criará 2^31 instâncias de Long desnecessárias. Desta forma, “prefira tipos primitivos a objetos que os encapsulem e tome cuidado nos autoboxing não intencionais”.

Essa parte do livro foi muito interessante pois são situações diárias e que se não forem observadas podem contribuir para diminuir a performance de aplicações.

Segue o link do livro.

 

10 conselhos de um bom programador

Para se tornar um bom profissional (e isso vale para qualquer área eu acho) é preciso muita dedicação no estudo da teoria e muito mais ainda na aplicação da prática.

Dominar certa tecnologia, técnica ou ferramenta requer muita tentativa, erro e mais tentativa. Até que se chegue ao acerto.

Quando resolvi escrever isso aqui eu pensava em direcionar a lista pra quem ta começando. Mas se me permitem acho que posso ir além. A lista mais abaixo vai trazer 10 ações que considero essenciais para aprender e dominar certa tecnologia. Isso envolve aprender uma linguagem, utilizar um framework, aprender sobre IA, fazer uma faculdade, criar um app e por aí vai.

Embora nunca tenha trabalhado em uma multinacional, startup, ou empresa grande de tecnologia, minha experiência permite que eu possa de forma humilde compilar esta lista. Sem nenhuma arrogância, pois preciso e espero ainda aprender muito. E é muito mesmo.

Então vamos à lista.

1 – Comece. Você vai conseguir;

2 – Comece do início. Não pule etapas. Se você quer aprender um framework, conheça primeiro a linguagem.

3 – Estruture seu conhecimento. Tem um monte de conteúdo, site, canal, blog etc por aí. Mas se você puder comprar um curso e um livro você vai aprender melhor e mais rápido.

4 – Invista em você. Se sentir que está na hora de alcançar outro patamar em sua carreira e pra isso deve fazer um curso que custa um pouco mais, tome a decisão certa na hora certa e faça.

5 – Segure a ansiedade. Não dá pra aprender, fazer, comprar, acompanhar, ler, escrever, gravar, postar, estudar tudo ao mesmo tempo sobre tudo. Calma.

6 – Persista. Se não deu certo hoje, saia, descanse, vá à academia, distraia, beba, esqueça. Amanhã vai funcionar. E outra, se não conseguiu aquela vaga, amanhã aparece outra.

7 – Não acumule dúvidas. Se você leu uma palavra sequer que não entendeu procure seu significado imediatamente. Se aparecer algum assunto relacionado e que você não entenda, pare, pesquise e depois volte. Vai fazer uma diferença e tanto depois.

8 – Pratique. Crie, recrie, copie. Crie um repositório no git e tente recriar site, app, interface etc. Teste seus conhecimentos mas sem cobranças exagaredas.

9 – Compartilhe. É muito clichê e também muito verdade. Uma vez que aprendeu, ensinar ou ajudar alguém vai fazer com que você nunca mais esqueça. E é gratificante demais.

10 – Tenha um hobby. Faça alguma atividade em outra área. Isso ajuda em tudo, inclusive na ansiedade.

Acho que é isso. Espero que possa ajudar e se você quiser acrescentar mais alguma coisa comente aí.

Abçs.

Um extra: se estiver com medo ou inseguro, é assim mesmo. Vai com medo mesmo.

Indicação de livro #01 – Análise de Tráfego em Redes TCP/IP

Inauguro esta nova área no blog indicando este livro que é indispensável para quem gosta e estuda a área.

O livro é dividio em cinco partes:

Conceitos básicos;

Protocolos e sua análise;

Conhecimentos específicos e sua análise;

Tráfegos diversos e sistemas específicos.

Além disso é feita uma ampla abordagem sobre protocolos de rede e assuntos correlatos, como IPv4, IPv6, TCP, UDP, ICMP, Ethernet, ARP e NDP, Modelo OSI, roteamento em redes, bridges e sistemas de firewall.

Pra quem curte pentest e segurança, é indispensável.

E você compra pelo link abaixo com desconto e me ajuda.

Ubuntu Apparmor impedindo MySQL Workbench de guardar senhas

Ao tentar criar uma conexão, me deparei com um erro quando tentava armazenar a senha.

Depois de muito pesquisar identifiquei que se tratava do apparmor, um serviço que garante ou remove privilégios de programas.

O mysql-workbench foi instalado pela Loja do Ubuntu no diretório /snap.

Depois de tentar criar uma entrada pelo apparmor vi uma solução mais simples.

Na apresentação do aplicativo na loja tem as opções de permissões. Depois de acessá-la foi só garantir ao programa a letira/edição de senhas.

Permissões para o apparmor

Instalação MySQL via Docker com acesso pelo workbench

O que parece ser trivial pode acabar demandando configurações extras além do que escrito no Docker hub.

No guia de instalação em https://hub.docker.com/r/mysql/mysql-server o comando docker run permite o acesso via -it com docker exec sem problemas.

O problema surge quando necessário acessar via workbench, o que é mais usual.

O problema: o usuário root com senha padrão gerada na instalação não tem permissão para acessar pelo localhost via TCP/IP. Que no caso do docker é tido como uma conexão remota.

Solução: primeiramente foi necessário expor a porta 3306 da imagem. Também aproveitei para setar uma senha por meio de parâmetro no comando run.

docker run --name mysql-server -e MYSQL_ROOT_PASSWORD=password-p3306:3306 -d mysql/mysql-server:5.6

Após a imagem instalada foi necessário garantir privilégios ao usuário root para acesso de qualquer host por meio dos comandos a seguir:

docker exec -it mysql-server mysql -uroot -p

grant all privileges on *.* to 'root'@'%' identified by 'password' with grant option;

Para entender melhor o esquema de senhas e hash do MySQL segue o tópico da documentação: https://dev.mysql.com/doc/refman/5.6/en/password-hashing.html

Depois de garantido o acesso é só configurar a conexão pelo workbench com o host localhost e senha previamente criada.

E pronto!

Styled Components FlatList ReactNative CSS problem

Something happens when a FlatList decorated with Styled Components update your data: the CSS of the Content disappears.

Bellow the original code and then the fix.

The CSS:
import styled from 'styled-components/native';
import DefaultButton from '~/components/Button';
export const Container = styled.View`
flex: 1;
background: #fff;
border-radius: 4px;
margin-bottom: 10px;
`;
export const Image = styled.Image`
width: auto;
height: 200;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
`;
export const Content = styled.View`
flex: 1;
padding: 15px;
`;
export const Title = styled.Text`
color: #333;
font-size: 16px;
font-weight: bold;
margin: 10px 0;
`;
export const Info = styled.Text`
color: #ccc;
font-size: 12px;
margin: 6px 0 6px 15px;
`;
export const Button = styled(DefaultButton)`
margin-top: 10px;
`;
The FlatList:
return (
<Background>
<Container>
<MeetupList
data={subscriptions}
keyExtractor={item=>String(item.id)}
renderItem={({item}) => (
<Meetup
data={item.meetup}
onHandle={() =>handleCancel(item.id)}
buttonText="Cancelar inscrição"
/>
)}
/>
</Container>
</Background>
);
The fix is set the Content flex-shrink to auto in the Content styled component.
export const Content = styled.View`
flex: 1 auto;
padding: 15px;
`;

SpringBoot @Async methods

Today I needed to implement a method to send a notification email after the registration progress. With the actual logic my application was taking too long during the process. So I decide to make the mail sending asynchronous.

First I tried the JMS, the old school Java Message Service API, but I realized that is not that gold, just old.

So after few googling I found a post of Dan Vega, a SpringBoot guru who has courses on Udemy.

With this post I realized: spring make our lives too easy, indeed.

Tow annotations make the method asynchronous, @Async and @EnableAsync.

Here is the post.