O documento fornece diretrizes sobre melhores práticas para classes, métodos, exceções e uso de strings e coleções em Java. As principais diretrizes incluem: (1) dar acesso restrito às classes e variáveis, (2) preferir composição à herança, (3) validar parâmetros, documentar métodos e tratar exceções adequadamente, (4) evitar uso desnecessário de null e strings imutáveis.
4. Classes e Interfaces
Visibilidade
{ } Faça com que cada classe ou variável tenha o acesso mais restrito
possível
{ } Variáveis de instância nunca devem ser públicas
public StatusCliente status = StatusCliente.ATIVO;
protected StatusCliente status = StatusCliente.ATIVO;
5. Classes e Interfaces
Desacoplamento
{ } Evite ao máximo o acoplamento entre classes ou componentes
conta1.getExtratoFisico();
GeradorExtrato.geraExtratoFisico(conta1);
6. Classes e Interfaces
Singletons
{ } Declare a variável de instância final e o construtor private
{ } Singletons para aplicações multithread
public static Banco getInstance() {
if (banco == null) {
banco = new Banco();
}
return banco;
}
7. Classes e Interfaces
Singletons
{ } Declare a variável de instância final e o construtor private
{ } Singletons para aplicações multithread
public static Banco getInstance() {
if (banco == null) {
synchronized (Banco.class) {
if (banco == null) {
banco = new Banco();
}
}
}
return banco;
}
8. Classes e Interfaces
Criação de Objetos
{ } Evite criar objetos desnecessários
public String geraExtratoOnline() {
Integer ag = this.getAgencia();
Long cc = this.getNumeroConta();
List<Movimentacao> e = this.getExtrato();
// ...
StringBuilder extrato = new StringBuilder();
extrato.append(montaCabecalho(ag, cc));
for(Movimentacao m : e){
extrato.append(m.getDataMovimentacao()).append(";");
extrato.append(m.getTipoMovimentacao());
extrato.append(";").append(m.getValor()).append("n"); }
// ...
return extrato.toString();
}
9. Classes e Interfaces
Criação de Objetos
{ } Evite criar objetos desnecessários
public String geraExtratoOnline() {
// ...
StringBuilder extrato = new StringBuilder();
extrato.append(montaCabecalho(this.getAgencia(), this.getNumeroConta()));
for(Movimentacao m : this.getExtrato()){
extrato.append(m.getDataMovimentacao()).append(";");
extrato.append(m.getTipoMovimentacao());
extrato.append(";").append(m.getValor()).append("n"); }
// ...
return extrato.toString();
}
10. Classes e Interfaces
Estáticos x Não Estáticos
{ } Prefira elementos estáticos a não estáticos
conta1.getExtratoFisico();
GeradorExtrato.geraExtratoFisico(conta1);
11. Classes e Interfaces
Encapsulamento
{ } Proteja as variáveis de sua classe através de getters e setters
public StatusCliente status = StatusCliente.ATIVO;
protected StatusCliente status = StatusCliente.ATIVO;
14. Classes e Interfaces
Interfaces
{ } Use interface apenas para definição de tipos
public abstract class Cliente implements Bloqueavel, StatusCliente {
public int status = ATIVO;
// ...
}
15. Classes e Interfaces
Interfaces
{ } Use interface apenas para definição de tipos
public enum StatusCliente { ATIVO, BLOQUEADO }
public abstract class Cliente implements Bloqueavel {
protected StatusCliente status = StatusCliente.ATIVO;
// ...
}
16. Classes e Interfaces
Classes Final
{ } Avalie cuidadosamente o design de sua aplicação para definir quando
uma classe deve ser declarada como final ou não
public final class Banco { /** … */ }
public final class Banco { /** … */ }
18. Métodos
Validação
< > Validação dos parâmetro da classe
public final void transfere(...) throws ... {
// Validação dos parâmetros.
ValidaParametrosDeTransferencia( ... );
}
19. Métodos
Assinatura
< > Escolha corretamente as assinaturas de métodos
public abstract class Cliente implements Bloqueavel {
// ...
public abstract String getCliente();
// ...
}
20. Métodos
Assinatura
< > Escolha corretamente as assinaturas de métodos
public abstract class Cliente implements Bloqueavel {
// ...
public abstract String getNome();
// ...
}
21. Métodos
Varargs
< > Utilize varargs com cautela
private static String montaRodape(String... param) {
BigDecimal saldo = new BigDecimal(param[0]);
StringBuilder rodape = new StringBuilder();
rodape.append("Seu saldo atual é ").append(saldo.toPlainString())
.append("n");
int i =0;
for (String aviso : param) {
if (i != 0){
rodape.append(aviso).append("n");
}
i++;
}
return rodape.toString();
}
22. Métodos
Varargs
< > Utilize varargs com cautela
private String montaRodape(BigDecimal saldo, String... avisos) {
StringBuilder rodape = new StringBuilder();
rodape.append("Seu saldo atual é ").append(saldo.toPlainString())
.append("n");
for (String aviso : avisos) {
rodape.append(aviso).append("n");
}
return rodape.toString();
}
23. Métodos
Javadoc
< > Lembre-se de documentar sempre seus métodos, especialmente os
métodos expostos em API’s
private void
final
final
final
validaParametrosDePagamento(
Conta contaOrigem,
BigDecimal valorBoleto,
String codigoDeBarras )
throws IllegalArgumentException { ... }
24. Métodos
Javadoc
< > Lembre-se de documentar sempre seus métodos, especialmente os
métodos expostos em API’s
/**
* Validador dos parâmetros de entrada da função efetuaPagamento(..).
* Valida se a conta não é nulas, se o valor valorDoBoleto é positivo
* e não nulo e se o codigoDeBarras não é nulo.
* @param contaOrigem
* @param valorBoleto
* @param codigoDeBarras
*/
private void validaParametrosDePagamento(
final Conta contaOrigem,
final BigDecimal valorBoleto,
final String codigoDeBarras )
throws IllegalArgumentException { ... }
26. Exceptions e Logging
Tratamento e Catches Genéricos
[ ] Nunca 'suma' com a exception
public String geraExtratoFisico() {
// ...
Writer writer = null;
try {
// ...
writer.close();
} catch (Exception e) { }
// ...
}
27. Exceptions e Logging
Tratamento e Catches Genéricos
[ ] Nunca 'suma' com a exception
} catch (FileNotFoundException e) {
log.severe(String.format("Ocorreu um erro ao gerar o arquivo: %s", e));
} catch (UnsupportedEncodingException e) {
log.severe(String.format("Encoding incorreto na hora de gerar um arquivo: %s", e));
} catch (IOException e) {
log.severe(String.format("Erro fatal de I/O, contate o administrador do sistema: %s“
, e));
} finally {
try {writer.close();}
catch (Exception ex) {
log.warning(String.format("Erro ao finalizar a escrita do arquivo de extrato: %s"
, ex));
}
}
28. Exceptions e Logging
Declarações Específicas
[ ] Declare exceptions específicas que o seu método pode lançar
public abstract void sacar(BigDecimal valorSaque)
throws Exception;
public abstract void sacar(BigDecimal valorSaque)
throws ContaBloqueadaException,
SaldoInsuficienteException;
29. Exceptions e Logging
Exception Original e Throw | Log
[ ] Carregue sempre a exception original ao lançar uma nova
[ ] Logue a exception apenas uma vez
try {
banco.transfere(conta1,
conta2,
new BigDecimal(50l),
"Divida Antiga");
} catch (Exception e) {
log.info("Erro ao transferir " + e.getMessage());
throw new Exception(e.getMessage());
}
30. Exceptions e Logging
Exception Original e Throw | Log
[ ] Carregue sempre a exception original ao lançar uma nova
[ ] Logue a exception apenas uma vez
try {
banco.transfere(conta1,
conta2,
new BigDecimal(50l),
"Divida Antiga");
} catch (Exception e) {
log.info("Erro ao transferir " + e.getMessage());
}
31. Exceptions e Logging
Bloco Finally e Relevância
[ ] Nunca lance uma exception de dentro do bloco finally
[ ] Só capture exceptions que você realmente for tratar
[ ] Lance apenas exceptions relevantes
[ ] Lembre-se de colocar informações relevantes na sua exception
finally {
try {
writer.close();
} catch (IOException ex) {
throw new Exception(e.getMessage());
}
}
32. Exceptions e Logging
Bloco Finally e Relevância
[ ] Nunca lance uma exception de dentro do bloco finally
[ ] Só capture exceptions que você realmente for tratar
[ ] Lance apenas exceptions relevantes
[ ] Lembre-se de colocar informações relevantes na sua exception
finally {
try {writer.close();} catch (IOException ex) {
log.warning(String.format("Erro ao finalizar (...) de extrato: %s", ex));
}
}
33. Exceptions e Logging
Throw early catch late
[ ] Lance a exception o quanto antes
[ ] Aguarde para ter informações suficientes para trata-lá
public final void efetuaPagamento(...) throws Exception {
validaParametrosDePagamento(contaOrigem, valorBoleto, codigoDeBarras);
try {
contaOrigem.sacar(valorBoleto);
} catch (Exception e) {
e.printStackTrace();
}
// ...
}
34. Exceptions e Logging
Throw early catch late
[ ] Lance a exception o quanto antes
[ ] Aguarde para ter informações suficientes para trata-lá
public final void efetuaPagamento(...)
throws ContaBloqueadaException, IllegalArgumentException {
validaParametrosDePagamento(contaOrigem, valorBoleto, codigoDeBarras);
contaOrigem.sacar(valorBoleto);
// ...
}
35. Exceptions e Logging
Controle de Fluxo
[ ] NUNCA utilize exceptions para controlar seu fluxo de execução
try{
if (param.length <= 0){
throw new Exception("Avisos e Saldo invalidos");
}
// ...
return rodape.toString();
} catch(Exception e){
return "";
}
36. Exceptions e Logging
Reutilização
[ ] Tente ao máximo utilizar exceptions já existentes
[ ] Não crie exceptions novas se não houver informações realmente utéis
private void validaParametrosDePagamento( ... ) throws ErroDeValidacaoException;
private void validaParametrosDePagamento( ... ) throws IllegalArgumentException;
37. Exceptions e Logging
Encapsulamento
[ ] Sempre que possível encapsule suas checked exceptions em
unchecked exceptions
[ ] Uma regra razoável é que se o cliente pode se recuperar de uma
exceção então ela deveria ser checked, caso contrário unchecked. Uma
exceção a essa regra são as exceções IllegalArgumentException,
NullpointerException e IllegalStateException
38. Exceptions e Logging
Performance
[ ] Lembre-se que exceptions podem impactar (muito) a performance do
software
[ ] * Um teste de 10000000 de iterações com com controle de fluxo usando
=> boolean ~ 62ms
=> Exception ~ 20891ms
* http://stackoverflow.com/questions/567579/how-expensive-are-exceptions
39. Exceptions e Logging
Log Level
[ ] Trace: Imagine que é proibido usar o “debug” da ide, neste trace deve-se
colocar todo o contexto necessário para o entendimento do “contexto”, estado
atual das variáveis.
[ ] Debug: informações para se ter uma visão do fluxo e das variáveis
[ ] Info: Eventos esporádicos inicialização e finalização de componentes, “setup”
[ ] Warn: Indica uma situação onde existe um erro temporário, degradação, um
possível problema e deve-se observar
[ ] Error: Não deveriam ocorrer, indicam a execução de um fluxo alternativo
[ ] Fatal: Erros fatais onde há ‘morte’ e não há como o sistema se
recuperar
40. Exceptions e Logging
Log Level
log.finest("Gerando extrato online para a conta: " + conta.toString());
log.info("O extrato foi gerado com sucesso");
log.warning(String.format("Erro ao gravar no arquivo de extrato: %s", ex));
log.severe(String.format("Erro fatal de I/O, contate o admin do sistema: %s", e));
41. Exceptions e Logging
Javadoc
[ ] Documente suas exceptions
/**
* Efetua um pagamento com base no número do código de barras.
* @param contaOrigem
* @param valorBoleto
* @param codigoDeBarras
* @throws SaldoInsuficienteException Quando não há saldo
* @throws ContaBloqueadaException Caso o cliente esteja bloqueado
* @throws IllegalArgumentException caso a validação falhe para algum dos parametros
*/
public final void efetuaPagamento( ... )
throws SaldoInsuficienteException,
ContaBloqueadaException,
IllegalArgumentException
43. Uso do Null
Pontos comuns para NPE
{ } Chamada de métodos de objetos não inicializados
{ } Parâmetros passados como null
Conta conta1 = null;
Conta conta2 = null;
try {
conta1 = // ... código de inicialização
conta2 = // ... código de inicialização
} catch (Exception e) {
e.printStackTrace();
}
log.info("realizando tranferencia da conta"
+ conta1.getNumeroConta()
+ " para "
+ conta2.getNumeroConta());
44. Uso do Null
Pontos comuns para NPE
{ } Chamada de métodos de objetos não inicializados
{ } Parâmetros passados como null
final Conta conta1 = new ContaPoupanca(999l, 1, cliente2);
final Conta conta2 = new ContaCorrente(171l, 24, cliente1);
try {
conta1.depositar(new BigDecimal("10000"));
} catch (ContaBloqueadaException e) {
log.warning("Não foi possivel incluir fundos nesta conta, ela encontra-se bloqueada");
}
45. Uso do Null
Pontos comuns para NPE
{ } Evite retornar null em metodos cujo retorno definido sejam coleções ou arrays
public List<Movimentacao> getExtrato() {
if (movimentacoes == null) return null;
Collections.sort(movimentacoes);
return movimentacoes;
}
46. Uso do Null
Pontos comuns para NPE
{ } Evite retornar null em metodos cujo retorno definido sejam coleções ou arrays
public List<Movimentacao> getExtrato() {
Collections.sort(movimentacoes);
return movimentacoes;
}
48. Strings
Criação de Strings
< > inicialização lenta
String msg = new String("O extrato foi gerado com sucesso“);
Log.info(msg);
< > inicialização rápida
String msg = "O extrato foi gerado com sucesso“;
Log.info(msg);
49. Strings
Alteração de Strings
< > Lembre-se: objetos do tipo String são imutáveis!
public String toString() {
String ag = String.valueOf(agencia);
String cc = String.valueOf(numeroConta);
cc.replaceAll("-","");
return "Conta{" + "agencia=" + ag + ", numeroConta=" + cc + '}';
}
50. Strings
Alteração de Strings
< > Lembre-se: objetos do tipo String são imutáveis!
public String toString() {
String ag = String.valueOf(agencia);
String cc = String.valueOf(numeroConta);
cc = cc.replaceAll("-","");
return "Conta{" + "agencia=" + ag + ", numeroConta=" + cc + '}';
}
51. Strings
Alteração de Strings
< > Use o operador ‘+’ se todos os operandos forem constantes
String s = s1 + s2
É transformado em:
String s = new StringBuilder(s1).append(s2).toString();
52. Strings
Alteração de Strings
< > Use StringBuilder dentro de um loop para atualização
< > Use StringBuilder ao invés de reatribuir valores a mesma variável
private static String montaRodape(String... param) {
// ...
String rodape = "";
rodape = rodape + "Seu saldo atual é " + saldo.toPlainString() + "n";
// ...
for (String aviso : param) {
if (i != 0){
String msg = aviso + "n";
rodape = rodape + msg;
}
i++;
}
53. Strings
Alteração de Strings
< > Use StringBuilder dentro de um loop para atualização
< > Use StringBuilder ao invés de reatribuir valores a mesma variável
private static String montaRodape(BigDecimal saldo, String... avisos) {
StringBuilder rodape = new StringBuilder();
rodape.append("Seu saldo atual é ").append(saldo.toPlainString()).append("n");
for (String aviso : avisos) {
rodape.append(aviso).append("n");
}
return rodape.toString();
}
58. I/O
Cuidados com I/O
( ) Você cuida dos recursos abertos por você
try { writer.close(); } catch (Exception ex) {
log.warning(
String.format("Erro ao finalizar a escrita do arquivo de extrato: %s", ex)
);
}
59. I/O
Cuidados com I/O
( ) Java é independente de plataforma, mas I/O não
writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(nomeArquivoExtrato), "utf-8“)
);