Como simplificar uma implementação compareTo () com segurança nula?
Estou implementandocompareTo()
método para uma classe simples como essa (para poder usarCollections.sort()
e outros brindes oferecidos pela plataforma Java):
public class Metadata implements Comparable<Metadata> {
private String name;
private String value;
// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}
eu quero oordenação natural para que esses objetos sejam: 1) classificados por nome e 2) classificados por valor se o nome for o mesmo; ambas as comparações não diferenciam maiúsculas de minúsculas. Para ambos os campos, os valores nulos são perfeitamente aceitáveis, portantocompareTo
não deve quebrar nesses casos.
A solução que vem à mente é a seguinte: (estou usando "cláusulas de guarda" aqui, enquanto outros podem preferir um único ponto de retorno, mas isso não vem ao caso):
// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(Metadata other) {
if (this.name == null && other.name != null){
return -1;
}
else if (this.name != null && other.name == null){
return 1;
}
else if (this.name != null && other.name != null) {
int result = this.name.compareToIgnoreCase(other.name);
if (result != 0){
return result;
}
}
if (this.value == null) {
return other.value == null ? 0 : -1;
}
if (other.value == null){
return 1;
}
return this.value.compareToIgnoreCase(other.value);
}
Isso faz o trabalho, mas não estou perfeitamente feliz com esse código. É certo que não émuito complexo, mas é bastante detalhado e tedioso.
A questão é,como você faria isso menos detalhado (mantendo a funcionalidade)? Sinta-se à vontade para consultar as bibliotecas padrão Java ou o Apache Commons, se elas ajudarem. A única opção para tornar isso (um pouco) mais simples seria implementar meu próprio "NullSafeStringComparator" e aplicá-lo para comparar os dois campos?
Edições 1-3: Eddie está certo; Corrigido o caso "ambos os nomes são nulos" acima
Sobre a resposta aceitaEu fiz essa pergunta em 2009, no Java 1.6, é claro, e na épocaa solução JDK pura de Eddie foi minha resposta aceita preferida. Eu nunca mudei para mudar isso até agora (2017).
Há tambémSoluções de bibliotecas de terceiros—Uma coleção Apache Commons 2009 e uma goiaba 2013, ambas postadas por mim — que eu preferia em algum momento.
Agora fiz a limpezaSolução Java 8 por Lukasz Wiktor a resposta aceita. Definitivamente, isso deve ser preferido no Java 8 e atualmente o Java 8 deve estar disponível para quase todos os projetos.