Por exemplo, para manter uma CPU ativada no Android, posso usar um código como este:
PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "abc");
wakeLock.acquire();
mas acho que as variáveis locais powerManager
e wakeLock
podem ser eliminadas:
((PowerManager)getSystemService(POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag")
.acquire();
cena semelhante aparece na visualização de alerta do iOS, por exemplo:
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"my title"
message:@"my message"
delegate:nil
cancelButtonTitle:@"ok"
otherButtonTitles:nil];
[alert show];
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[alertView release];
}
para:
[[[UIAlertView alloc]
initWithTitle:@"my title"
message:@"my message"
delegate:nil
cancelButtonTitle:@"ok"
otherButtonTitles:nil] show];
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[alertView release];
}
É uma boa prática eliminar uma variável local se ela for usada apenas uma vez no escopo?
Respostas:
O código é lido com muito mais frequência do que está escrito; portanto, você deve ter pena da pobre alma que terá que ler o código daqui a seis meses (pode ser você) e se esforçar para obter o código mais claro e fácil de entender. Na minha opinião, a primeira forma, com variáveis locais, é muito mais compreensível. Eu vejo três ações em três linhas, em vez de três ações em uma linha.
E se você pensa que está otimizando alguma coisa se livrando de variáveis locais, não está. Um compilador moderno colocará
powerManager
um registro 1 , independentemente de uma variável local ser usada ou não, para chamar onewWakeLock
método. O mesmo vale parawakeLock
. Então você acaba com o mesmo código compilado em ambos os casos.1 Se você tivesse muito código intermediário entre a declaração e o uso da variável local, ele pode ficar na pilha, mas é um detalhe menor.
fonte
Alguns comentários altamente votados afirmaram isso, mas nenhuma das respostas que vi fizeram, por isso vou adicioná-lo como resposta. Seu principal fator na decisão desse problema é:
Debuggability
Freqüentemente, os desenvolvedores gastam muito mais tempo e esforço na depuração do que escrevendo código.
Com variáveis locais, você pode:
Ponto de interrupção na linha em que foi atribuído (com todas as outras decorações de ponto de interrupção, como ponto de interrupção condicional, etc ...)
Inspecione / observe / imprima / altere o valor da variável local
Problemas de captura que surgem devido a elencos.
Ter rastreamentos de pilha legíveis (a linha XYZ tem uma operação em vez de 10)
Sem variáveis locais, todas as tarefas acima são muito mais difíceis, extremamente difíceis ou absolutamente impossíveis, dependendo do seu depurador.
Como tal, siga a máxima infame (escreva o código da maneira que você faria como se o próximo desenvolvedor a manter depois de si mesmo seja um lunático louco que sabe onde você mora) e erre no lado de uma depuração mais fácil , ou seja, use variáveis locais .
fonte
Somente se tornar o código mais fácil de entender. Nos seus exemplos, acho que fica mais difícil de ler.
Eliminar as variáveis no código compilado é uma operação trivial para qualquer compilador respeitável. Você pode inspecionar a saída para verificar.
fonte
Sua pergunta "é uma boa prática eliminar uma variável local se for usada apenas uma vez no escopo?" está testando os critérios errados. O utilitário de uma variável local não depende do número de vezes que é usado, mas se torna o código mais claro. Rotular valores intermediários com nomes significativos pode melhorar a clareza em situações como a que você apresenta, pois divide o código em blocos menores e mais digeríveis.
Na minha opinião, o código não modificado que você apresentou é mais claro que o código modificado e, portanto, deve permanecer inalterado. De fato, eu consideraria extrair uma variável local do seu código modificado para melhorar a clareza.
Eu não esperaria nenhum impacto no desempenho das variáveis locais e, mesmo que exista, é provável que seja pequeno demais para ser considerado, a menos que o código esteja em um loop muito restrito em uma parte crítica da velocidade do programa.
fonte
Talvez.
Pessoalmente, hesitaria em eliminar as variáveis locais se um typecast estiver envolvido. Acho sua versão compacta menos legível quando o número de colchetes começa a se aproximar de um limite mental que eu tenho. Ele até introduz um novo conjunto de colchetes que não era necessário na versão um pouco mais detalhada usando uma variável local.
O destaque da sintaxe fornecido pelo editor de código pode atenuar essas preocupações em certa medida.
Para meus olhos, este é o melhor compromisso:
Mantendo assim uma variável local e abandonando a outra. Em C #, eu usaria a palavra-chave var na primeira linha, pois o typecast já fornece as informações de tipo.
fonte
Embora eu aceite a validade das respostas que favorecem as variáveis locais, vou interpretar o advogado do diabo e apresentar uma visão contrária.
Pessoalmente, sou contra o uso de variáveis locais exclusivamente para fins de documentação, embora esse próprio motivo indique que a prática tem valor: as variáveis locais efetivamente pseudo-documentam o código.
No seu caso, o principal problema é o recuo e não a ausência de variáveis. Você pode (e deve) formatar o código da seguinte maneira:
Compare isso com a versão com variáveis locais:
Com as variáveis locais: os nomes adicionam algumas informações ao leitor e os tipos são claramente especificados, mas as chamadas de método reais são menos visíveis e (na minha opinião) não são lidas com clareza.
Sem usar variáveis locais: é mais conciso e as chamadas de método são mais visíveis, mas você pode solicitar mais informações sobre o que está sendo retornado. Alguns IDEs podem mostrar isso no entanto.
Mais três comentários:
Na minha opinião, adicionar código que não tem uso funcional às vezes pode ser confuso, pois o leitor deve perceber que ele realmente não tem uso funcional e simplesmente existe para "documentação". Por exemplo, se esse método tivesse 100 linhas, não seria óbvio que as variáveis locais (e, portanto, o resultado da chamada do método) não fossem necessárias em algum momento posterior, a menos que você leia o método inteiro.
A adição de variáveis locais significa que você deve especificar seus tipos, e isso introduz uma dependência no código que, de outra forma, não estaria lá. Se o tipo de retorno dos métodos mudasse trivialmente (por exemplo, ele foi renomeado), você teria que atualizar seu código, enquanto que, sem as variáveis locais, não seria.
A depuração poderia ser mais fácil com variáveis locais se o depurador não mostrar valores retornados dos métodos. Mas a correção para isso é corrigir as deficiências nos depuradores, não alterar o código.
fonte
with
declarações. Seriam convenções de formatação normais em Java.Há uma tensão de motivações aqui. A introdução de variáveis temporárias pode facilitar a leitura do código. Mas eles também podem impedir e dificultar a visualização de outras refatorações possíveis, como o Método de Extração e Substituir Temp por Consulta . Esses últimos tipos de refatoração, quando apropriado, geralmente oferecem benefícios muito maiores do que a variável temp.
Sobre as motivações para essas refatorações, Fowler escreve :
Portanto, sim, use temporários se eles tornarem o código mais legível, principalmente se for uma norma local para você e sua equipe. Mas esteja ciente de que fazer isso às vezes pode dificultar a identificação de melhorias alternativas maiores. Se você pode desenvolver sua capacidade de sentir quando vale a pena ficar sem essas temperaturas e se sentir mais confortável ao fazê-lo, isso provavelmente é uma coisa boa.
FWIW Eu pessoalmente evitei ler o livro de Fowler "Refatoração" por dez anos, porque imaginei que não havia muito a dizer sobre tópicos relativamente simples. Eu estava completamente errado. Quando finalmente o li, ele mudou minhas práticas diárias de codificação, para melhor.
fonte
Bem, é uma boa idéia eliminar variáveis locais se você puder tornar o código mais legível. Esse seu one-liner longo não é legível, mas segue um estilo OO bastante detalhado. Se você pudesse reduzi-lo a algo como
então eu diria que provavelmente seria uma boa ideia. Talvez você possa introduzir métodos auxiliares para reduzi-lo a algo semelhante; se um código como esse aparecer várias vezes, pode valer a pena.
fonte
Vamos considerar a Lei de Demeter aqui. No artigo da Wikipedia sobre LoD, o seguinte é afirmado:
Uma das conseqüências de seguir esta lei é que você deve evitar chamar métodos de objetos retornados por outros métodos em uma cadeia longa pontilhada, como é mostrado no segundo exemplo acima:
É realmente difícil descobrir o que isso está fazendo. Para entendê-lo, você precisa entender o que cada procedimento faz e decifrar qual função está sendo chamada em qual objeto. O primeiro bloco de código
mostra claramente o que você está tentando fazer - você está obtendo um objeto do PowerManager, obtendo um objeto WakeLock do PowerManager e adquirindo o wakeLock. A regra acima segue a regra nº 3 do LoD - você está instanciando esses objetos no seu código e, portanto, pode usá-los para fazer o que você precisa.
Talvez outra maneira de pensar é lembrar que, ao criar um software, você deve escrever com clareza, não com brevidade. 90% de todo o desenvolvimento de software é manutenção. Nunca escreva um código que você não gostaria de manter.
Boa sorte.
fonte
Uma coisa a notar é que o código é lido com freqüência, em diferentes "profundidades". Este código:
é fácil "roçar". São 3 afirmações. Primeiro, criamos um
PowerManager
. Então criamos umWakeLock
. Então nósacquire
owakeLock
. Eu posso ver isso com muita facilidade apenas olhando para o início de cada linha; atribuições de variáveis simples são realmente fáceis de reconhecer parcialmente como "Digite varName = ..." e apenas deslize mentalmente sobre o "...". Da mesma forma, a última afirmação obviamente não é a forma da tarefa, mas envolve apenas dois nomes; portanto, a "essência principal" é imediatamente aparente. Muitas vezes, isso é tudo que eu precisaria saber se estivesse apenas tentando responder "o que esse código faz?" em um nível alto.Se eu estou perseguindo um bug sutil que acho que está aqui, então obviamente precisarei revisar isso com muito mais detalhes e, na verdade, lembrarei dos "..." s. Mas a estrutura de declaração separada ainda me ajuda a fazer uma declaração de cada vez (especialmente útil se eu precisar aprofundar a implementação das coisas que são chamadas em cada declaração; quando eu voltar, eu entendi completamente "uma unidade" e pode passar para a próxima declaração).
Agora é tudo uma afirmação. A estrutura de nível superior não é tão fácil de ler rapidamente; na versão original do OP, sem quebras de linha e recuo para comunicar visualmente qualquer estrutura, eu teria que contar parênteses para decodificá-la em uma sequência de três etapas. Se algumas das expressões de várias partes estiverem aninhadas uma à outra, em vez de organizadas como uma cadeia de chamadas de método, ainda assim poderá parecer semelhante a isso, por isso tenho que ter cuidado ao confiar nisso sem contar parênteses. E se eu confio no recuo e apenas deslizo para a última coisa como o ponto presumido de tudo isso, o que
.acquire()
me diz por si só?Às vezes, porém, isso pode ser o que você deseja. Se eu aplicar sua transformação no meio do caminho e escrever:
Agora isso se comunica com um toque rápido "obtenha um
WakeLock
, entãoacquire
ele". Ainda mais simples que a primeira versão. É imediatamente óbvio que o que é adquirido é umWakeLock
. Se a obtenção de umPowerManager
é apenas um sub-detalhe que é bastante insignificante ao ponto deste código, maswakeLock
é importante, pode realmente ajudar a enterrar oPowerManager
material, de modo que é natural examiná-lo se você estiver apenas tentando obter rapidamente um idéia do que esse código faz. E, sem nomeá-lo, comunica que é usado apenas uma vez, e às vezes é o que é importante (se o restante do escopo for muito longo, eu teria que ler tudo isso para saber se é usado novamente; embora o uso de sub-escopos explícitos possa ser outra maneira de resolver isso, se o seu idioma os suportar).O que traz à tona que tudo depende do contexto e do que você deseja se comunicar. Como na escrita em prosa em linguagem natural, sempre existem muitas maneiras de escrever um determinado trecho de código que é basicamente equivalente em termos de conteúdo de informações. Como na escrita em prosa em linguagem natural, como você escolhe entre eles geralmente não deve aplicar regras mecanicistas como "eliminar qualquer variável local que ocorra apenas uma vez". Pelo contrário, comovocê optar por escrever o seu código enfatizará certas coisas e enfatizará outras. Você deve se esforçar para fazer essas escolhas conscientemente (incluindo a opção de escrever código menos legível por razões técnicas às vezes), com base no que você realmente deseja enfatizar. Pense especialmente no que servirá aos leitores que precisam apenas "entender o essencial" do seu código (em vários níveis), pois isso acontecerá com muito mais frequência do que uma leitura muito próxima de expressão por expressão.
fonte
getSystemService(POWER_SERVICE)
recebe o gerente de energia..newWakeLock
recebe um bloqueio de vigília..acquire
adquire. OK, não conheço todos os tipos, mas posso descobrir isso no IDE, se necessário.return
mais rápido possível dos métodos, pelo mesmo motivo.É até um antipadrão com seu próprio nome: Train Wreck . Vários motivos para evitar a substituição já foram mencionados:
Considere se esse método sabe muito de outros objetos. O encadeamento de métodos é uma alternativa que pode ajudá-lo a reduzir o acoplamento.
Lembre-se também de que as referências a objetos são realmente baratas.
fonte
A pergunta declarada é "Devemos eliminar variáveis locais, se pudermos"?
Não, você não deve eliminar apenas porque pode.
Você deve seguir as diretrizes de codificação em sua loja.
Na maioria das vezes, as variáveis locais facilitam a leitura e a depuração do código.
Eu gosto do que você fez
PowerManager powerManager
. Para mim, uma letra minúscula da classe significa que é apenas uma vez.Quando você não deveria, é se a variável vai se apegar a recursos caros. Muitos idiomas têm sintaxe para uma variável local que precisa ser limpa / liberada. Em C # está usando.
fonte
using(new SQLConnection()) { /* ... */ }
não fosse legal também (se seria útil é uma questão diferente :).Um aspecto importante não foi mencionado nas outras respostas: Sempre que você adiciona uma variável, você introduz um estado mutável. Isso geralmente é uma coisa ruim porque torna seu código mais complexo e, portanto, mais difícil de entender e testar. Obviamente, quanto menor o escopo da variável, menor o problema.
O que você deseja não é realmente uma variável cujo valor possa ser modificado, mas uma constante temporária. Portanto, considere expressar isso em seu código, se seu idioma permitir. Em Java você pode usar
final
e em C ++ você pode usarconst
. Na maioria das linguagens funcionais, esse é o comportamento padrão.É verdade que as variáveis locais são o tipo menos prejudicial de estado mutável. As variáveis de membro podem causar muito mais problemas e as variáveis estáticas são ainda piores. Ainda assim, acho importante expressar com a maior precisão possível em seu código o que ele deve fazer. E há uma enorme diferença entre uma variável que pode ser modificada posteriormente e um mero nome para um resultado intermediário. Portanto, se seu idioma permitir que você expresse essa diferença, faça-o.
fonte
getFoo()
. Se eu evitar uma declaração local, terminarei comif(getFoo() > 10) alert(getFoo());
Mas getFoo () pode retornar valores diferentes nas duas chamadas diferentes. Eu poderia enviar um alerta com um valor menor ou igual a 10, o que é confuso na melhor das hipóteses e voltará para mim como um defeito. Esse tipo de coisa se torna mais importante com a simultaneidade. A atribuição local é atômica.PowerManager
instância depois de chamar esse método? Deixe-me verificar o resto do método .... mmm ok não. E issoWakeLock
que você tem ... o que você está fazendo com isso (digitalizando o restante do método mais uma vez) ... mmm novamente nada ... ok, então por que eles estão lá? Ah, sim, deveria ser mais legível ... mas sem eles, tenho certeza que você não os usa mais, para que não precise ler o restante do método.final
for necessário em uma variável local em um método, seu método é muito longo.