:: Dúvida simples sobre performance e alocação de memória para criação de String

Pessoal,

Dúvida simples mas que vai dar muitas páginas de discussão.

Qual código é mais performático? Ou melhor, qual código necessitará de menos memória para execução?

	
	// Opção 1 : chamada de debug no log4j concatenando a mensagem na hora
	Logger.getLogger(this.getClass()).debug("O processo " + process.getName() + " finalizou em " + time);

	// Opção 2 : fazendo a verificação se o level de log esta ativo
	if( Logger.getLogger(this.getClass()).isDebugEnabled() ) { 
		Logger.getLogger(this.getClass()).debug("O processo " + process.getName() + " finalizou em " + time);
	}

	// Opção 3 : Usando constante para a mensagem de log
	public static final String MESSAGE_PROCESS_END = "O processo %s finalizou em %s";
	...
	Logger.getLogger(this.getClass()).debug(String.format(MESSAGE_PROCESS_END, process.getName(), time));

Ou será que existe uma combinação das opções acima que pode ser a ideal?

Outra coisa. Existe diferença entre:

	
	// Opção 1
	Logger log = Logger.getLogger(this.getClass());
	
	// Opção 2
	Logger log = Logger.getLogger(Teste.class);
	

Me disseram que o this.getClass() vai fazer a JVM usar reflection para descobrir qual a classe … lol … eu não acredito nisso, mas não custa perguntar para garantir.

Obrigado pelas opiniões.

Ps: Se algum moderador ou admin achar que este post não se enquadra na sessão off-topic, favor mover para a sessão correta … afinal, estou falando de java

[]'s

Em Las Vegas eu apostaria na #2! (Não em um teste isolado mas no uso “normal” do código)

Voce vai ter que olhar o bytecode resultante. Pega um heditor de hexa e compare os dois arquivos e veja a quantidade de linhas. Eu apostaria que daria tudo na mesma coisa.
Lembre-se que posteriormente o jit otimiza.

UP!

Eu diria que esse esquema de concatenar String com + hoje em dia não tem diferença nenhuma. Se fizer reverso do bytecode vai ver que ele otimisa pra você.

Na prática, sempre que o operador + é usado para concatenação de String o compilador instancia um StringBuilder e utiliza o append() para a concatenação. Mas mesmo assim é preciso tomar cuidado com o uso desse operador. Esse artigo esclarece muito bem o assunto:

http://blog.caelum.com.br/revisitando-a-concatenacao-de-strings-stringbuilder-e-stringbuffer/

a mesma coisa nos três abraços

Só o fato de você estar usando um logger significa que você estará realizando rotinas de IO, logo, acredito que todo ganho de performance que você ganharia com manipulação de Strings seria “perdido”. Quanto as opções:
Concatenação usando + , o java troca pelo uso de StringBuilder como o rmendes08 falou.
Então seria criado um StringBuider, uma String para "O processo " uma para " finalizou em " e uma para process.getName() e, claro, uma pelo método toString do objeto StringBuilder. Sem contar as chamadas ao método append.

A segunda forma, creio que seriam apenas Strings: “O processo %s finalizou em %s” , process.getName(). Usaria alguma técnica de replace para cada %s e um String resultante para cada replace, sendo o último replace a String final a ser apresentada.

(estou considerando que time não é uma String).
Qual é mais performática? Em termos de uso de memória, diria que é a segunda forma. Mas para ter certeza, usaria algum profiler.

O if que testa se o logger está ativo minimiza possíveis exceções geradas pelo mesmo, ou ao menos, evita chamadas desnecessárias.

Quanto a diferença do .getClass() e do class, o getClass() vai precisar saber qual o tipo real do objeto. O .class, retornará o objeto correto da classe.
Não sei se ocorre por reflexão ou por polimorfismo, mas prvavelmente é um desses, logo deve “gastar mais processamento”.

Segue um exemplo:

[code]interface Teste {}

class TesteImpl implements Teste {}

class TesteTesteImpl extends TesteImpl {}

public class Main {
public static void main(String[] args) {

	Teste teste = new TesteImpl();
	Teste teste1 = new TesteTesteImpl();
	TesteImpl teste2 = new TesteTesteImpl();

	//Usando .class
	System.out.println(Teste.class);
	System.out.println(TesteImpl.class);
	
	//Usando .getClass()
	System.out.println(teste.getClass());
	System.out.println(teste1.getClass());
	System.out.println(teste2.getClass());
	
}

}[/code]
Resultando em:

interface br.com.teste.Teste class br.com.teste.TesteImpl class br.com.teste.TesteImpl class br.com.teste.TesteTesteImpl class br.com.teste.TesteTesteImpl