Pergunta

String s = "";
for(i=0;i<....){
    s = some Assignment;
}

ou

for(i=0;i<..){
    String s = some Assignment;
}

Não preciso mais usar 's' fora do loop.A primeira opção talvez seja melhor, pois uma nova String não é inicializada todas as vezes.O segundo, entretanto, resultaria na limitação do escopo da variável ao próprio loop.

EDITAR:Em resposta à resposta de Milhous.Seria inútil atribuir a String a uma constante dentro de um loop, não seria?Não, aqui 'alguma Atribuição' significa um valor variável obtido da lista que está sendo iterada.

Além disso, a questão não é porque estou preocupado com o gerenciamento de memória.Só quero saber o que é melhor.

Foi útil?

Solução

Escopo limitado é melhor

Use sua segunda opção:

for ( ... ) {
  String s = ...;
}

O escopo não afeta o desempenho

Se você desmontar o código compilado de cada um (com o JDK javap ferramenta), você verá que o loop compila exatamente as mesmas instruções JVM em ambos os casos.Observe também que Brian R.Bondy's A "Opção nº 3" é idêntica à Opção nº 1.Nada extra é adicionado ou removido da pilha ao usar o escopo mais restrito, e os mesmos dados são usados ​​na pilha em ambos os casos.

Evite inicialização prematura

A única diferença entre os dois casos é que, no primeiro exemplo, a variável s é inicializado desnecessariamente.Esta é uma questão separada da localização da declaração da variável.Isso adiciona duas instruções desperdiçadas (para carregar uma constante de string e armazená-la em um slot de quadro de pilha).Uma boa ferramenta de análise estática irá avisá-lo de que você nunca está lendo o valor atribuído a s, e um bom compilador JIT provavelmente irá eliminá-lo em tempo de execução.

Você poderia corrigir isso simplesmente usando uma declaração vazia (ou seja, String s;), mas isso é considerado uma má prática e tem outro efeito colateral discutido abaixo.

Muitas vezes um valor falso como null é atribuído a uma variável simplesmente para silenciar um erro do compilador de que uma variável é lida sem ser inicializada.Este erro pode ser interpretado como uma dica de que o escopo da variável é muito grande e que está sendo declarado antes de ser necessário para receber um valor válido.Declarações vazias forçam você a considerar cada caminho de código;não ignore este aviso valioso atribuindo um valor falso.

Conservar slots de pilha

Conforme mencionado, embora as instruções da JVM sejam as mesmas em ambos os casos, há um efeito colateral sutil que torna melhor, no nível da JVM, usar o escopo mais limitado possível.Isso é visível na "tabela de variáveis ​​locais" do método.Considere o que acontece se você tiver vários loops, com as variáveis ​​declaradas em um escopo desnecessariamente grande:

void x(String[] strings, Integer[] integers) {
  String s;
  for (int i = 0; i < strings.length; ++i) {
    s = strings[0];
    ...
  }
  Integer n;
  for (int i = 0; i < integers.length; ++i) {
    n = integers[i];
    ...
  }
}

As variáveis s e n poderiam ser declarados dentro de seus respectivos loops, mas como não o são, o compilador usa dois "slots" no quadro da pilha.Se eles foram declarados dentro do loop, o compilador pode reutilizar o mesmo slot, diminuindo o quadro da pilha.

O que realmente importa

No entanto, a maioria destas questões são imateriais.Um bom compilador JIT verá que não é possível ler o valor inicial que você está atribuindo de forma desnecessária e otimizará a atribuição.Salvar um slot aqui ou ali não fará ou quebrará seu aplicativo.

O importante é tornar seu código legível e fácil de manter e, nesse aspecto, usar um escopo limitado é claramente melhor.Quanto menor o escopo de uma variável, mais fácil será compreender como ela é usada e qual o impacto que qualquer alteração no código terá.

Outras dicas

Dentro teoria, é um desperdício de recursos declarar a corda dentro do loop. Dentro prática, no entanto, os dois trechos que você apresentou se compilam com o mesmo código (declaração fora do loop).

Portanto, se o seu compilador fizer alguma quantidade de otimização, não há diferença.

Em geral, eu escolheria o segundo, porque o escopo da variável 'S' é limitado ao loop. Benefícios:

  • Isso é melhor para o programador, porque você não precisa se preocupar em ser usado novamente em algum lugar mais tarde na função
  • Isso é melhor para o compilador, porque o escopo da variável é menor e, portanto, pode fazer mais análise e otimização
  • Isso é melhor para futuros leitores, porque eles não se perguntam por que a variável 's' é declarada fora do loop se nunca for usada mais tarde

Se você deseja acelerar os loops, prefiro declarar uma variável máxima ao lado do balcão, para que não sejam necessárias pesquisas repetidas para a condição:

ao invés de

for (int i = 0; i < array.length; i++) {
  Object next = array[i];
}

eu prefiro

for (int i = 0, max = array.lenth; i < max; i++) {
  Object next = array[i];
}

Quaisquer outras coisas que devem ser consideradas já foram mencionadas, então apenas meus dois centavos (veja o post de Ericksons)

Greetz, Ghad

Para adicionar um pouco a @Resposta de Esteban Araya, ambos exigirão a criação de uma nova string a cada vez através do loop (como o valor de retorno do some Assignment expressão). Essas cordas precisam ser coletadas de lixo de qualquer maneira.

Eu sei que esta é uma pergunta antiga, mas pensei em acrescentar um pouco que é um pouco relacionado.

Percebi enquanto navegava no código-fonte Java que alguns métodos, como String.contentEquals (duplicado abaixo) tornam variáveis ​​locais redundantes que são apenas cópias de variáveis ​​de classe.Acredito que houve um comentário em algum lugar que implicava que acessar variáveis ​​locais é mais rápido do que acessar variáveis ​​de classe.

Neste caso, "v1" e "v2" são aparentemente desnecessários e poderiam ser eliminados para simplificar o código, mas foram adicionados para melhorar o desempenho.

public boolean contentEquals(StringBuffer sb) {
    synchronized(sb) {
        if (count != sb.length())
            return false;
        char v1[] = value;
        char v2[] = sb.getValue();
        int i = offset;
        int j = 0;
        int n = count;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
                return false;
        }
    }
    return true;
}

Parece -me que precisamos de mais especificações do problema.

o

s = some Assignment;

não é especificado sobre que tipo de tarefa é essa. Se a tarefa for

s = "" + i + "";

Então uma nova picada precisa ser alocada.

Mas se for

s = some Constant;

S apenas apontará para o local da memória das constantes e, portanto, a primeira versão seria mais eficiente em memória.

Parece que sou um pouco bobo em me preocupar com muita otimização de um loop para um Lang Imho interpretado.

Quando estou usando vários tópicos (mais de 50), achei que essa era uma maneira muito eficaz de lidar com problemas de tópicos fantasmas por não conseguir fechar um processo corretamente ... se eu estiver errado, por favor me saiba por que Estou errado:

Process one;
BufferedInputStream two;
try{
one = Runtime.getRuntime().exec(command);
two = new BufferedInputStream(one.getInputStream());
}
}catch(e){
e.printstacktrace
}
finally{
//null to ensure they are erased
one = null;
two = null;
//nudge the gc
System.gc();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top