Quando se deve usar final para parâmetros de método e variáveis ??locais?

StackOverflow https://stackoverflow.com/questions/154314

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu encontrei um par de referências ( por exemplo ) que sugerir o uso de final, tanto quanto possível e eu estou querendo saber como isso é importante. Isto é principalmente no contexto dos parâmetros do método e variáveis ??locais, e não métodos final ou classes. Para constantes, faz sentido óbvio.

Por um lado, o compilador pode fazer algumas otimizações e faz do programador intenção mais clara. Por outro lado, acrescenta verbosidade e as otimizações pode ser trivial.

É algo que eu deveria fazer um esforço para se lembrar?

Foi útil?

Solução

obsessivas com:

  • campos finais - campos de marcação como forças finais que possam ser estabelecidas pelo fim da construção, fazendo que imutável referência de campo. Isto permite a publicação segura de campos e pode evitar a necessidade de sincronização mais tarde lê. (Note-se que para uma referência de objeto, somente a referência de campo é imutável -. Coisas que referência de objeto refere-se ainda pode mudar e que afeta a imutabilidade)
  • campos estáticos finais -. Embora eu usar enums agora para muitos dos casos em que eu costumava usar campos finais estáticos

Considere mas utilizar judiciosamente:

  • classes finais -. Framework / design API é o único caso em que eu considerá-lo
  • métodos finais - Basicamente mesmo como classes finais. Se você estiver usando padrões Template Method como um louco e marcação material final, provavelmente você está confiando demais em herança e não o suficiente sobre delegação.

Ignorar a menos sentindo anal:

  • parâmetros de método e variáveis ??locais - Eu raramente fazer isso em grande parte porque eu sou preguiçoso e acho que é tumultua o código. Vou totalmente admitir que os parâmetros de marcação e variáveis ??locais que eu não vou para modificar é "Righter". Eu queria que fosse o padrão. Mas não é e eu encontrar o código mais difícil de entender com finais todo. Se estou no código de outra pessoa, eu não vou retirá-los, mas se eu estou escrevendo novo código não vou colocá-los em. Uma exceção é o caso onde você tem que marcar alguma coisa última que você possa acessar -lo de dentro de uma classe interna anônima.

Outras dicas

É algo que eu deveria fazer um esforço para se lembrar de fazer?

Não, se você estiver usando Eclipse, porque você pode configurar um Salvar ação para adicionar automaticamente esses final modificadores para você. Então você obter os benefícios para menos esforço.

Os benefícios de tempo de desenvolvimento de "final" são pelo menos tão significativo como os benefícios em tempo de execução. Diz futuros editores do código algo sobre suas intenções.

A marcação de uma classe "final" indica que você não tenha feito um esforço durante a concepção ou implementação da classe de extensão alça graciosamente. Se os leitores podem fazer alterações para a classe, e deseja remover o modificador "final", eles podem fazê-lo em seu próprio risco. Cabe a eles para garantir que a classe irá lidar com poço de extensão.

A marcação de uma variável de "final" (e atribuindo-lhe no construtor) é útil com injecção de dependência. Ele indica a natureza "colaborador" da variável.

A marcação de um método de "final" é útil em classes abstratas. Ele delineia claramente onde os pontos de extensão são.

eu encontrei marcação parâmetros do método e moradores como final é útil como uma ajuda refactoring quando o método em questão é uma bagunça incompreensível várias páginas. final Sprinkle liberalmente, ver o que "não pode atribuir a última variável" erros do compilador (ou seu IDE) lança-se, e você só pode descobrir por que a variável chamada "dados" acaba nula, embora vários (desatualizado) comenta juram que não pode acontecer.

Em seguida, você pode corrigir alguns dos erros, substituindo as variáveis ??reutilizados com novas variáveis ??declarou mais próximo do ponto de uso. Então você achar que você pode envolver partes inteiras do método no escopo chaves, e de repente você está keypress um IDE longe "Extract Method" e seu monstro ficou mais compreensível.

Se o seu método é não já uma destruição insustentável, eu acho que pode haver valor em fazer coisas final para desencorajar as pessoas de transformá-lo em disse naufrágio; mas se é um método de curta duração (ver: não unmaintainable), então você corre o risco adicionando um monte de verbosidade. Em particular, Java assinaturas de função são forte o suficiente para caber em 80 caracteres, pois é, sem acrescentar mais seis per argumento!

Eu uso final o tempo todo para fazer Java mais expressão base. condições See de Java (if,else,switch) não são expressão base que eu sempre odiei especialmente se o seu usado para programação funcional (ou seja, ML, Scala ou Lisp).

Assim, você deve tentar sempre (IMHO) usar variáveis ??finais ao usar condições.

Deixe-me dar um exemplo:

    final String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
        default:
            throw new IllegalStateException();
    }

Agora Se adicionar outra declaração case e não fazer set name o compilador irá falhar. O compilador também irá falhar se você não quebrar em cada caso (que você definir a variável). Isso permite que você faça Java muito semelhante ao expressões let do Lisp e torna tão seu código não é maciçamente recuado (por causa de variáveis ??de escopo léxico).

E como @Recurse notado (mas aparentemente -1 mim) você pode fazer o anterior sem fazer String name final para obter o erro do compilador (que eu nunca disse que não poderia), mas você pode facilmente fazer o erro de compilador ir embora definir nome após a instrução switch que joga fora a semântica de expressão ou pior esquecimento para break que você não pode causar um erro (apesar do que @Recurse diz) sem usar final:

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            //break; whoops forgot break.. 
            //this will cause a compile error for final ;P @Recurse
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

Por causa do nome da definição bug (além esquecendo de break que também outro bug) agora posso acidentalmente fazer isso:

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        //should have handled all the cases for pluginType
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

As forças variáveis ??finais uma única avaliação de qual nome deveria ser. Semelhante à forma como uma função que tem um valor de retorno deve sempre retornar um valor (exceções ignorando) o bloco de troca de nome terá de nome determinação e, portanto, obrigado a esse bloco interruptor que faz refatoração pedaços de código mais fácil (ou seja Eclipe refactor: Método de extrato) .

O acima em OCaml:

type plugin = CandidateExport | JobPostingImport

let p = CandidateExport

let name = match p with
    | CandidateExport -> "Candidate Stuff"
    | JobPostingImport -> "Blah" ;;

Os avalia match ... with ... como uma expressão de função ie. Observe como ele se parece com a nossa declaração switch.

Aqui está um exemplo no Esquema (raquete ou frango):

(define name 
    (match b
      ['CandidateExport "Candidate Stuff"]
      ['JobPostingImport "Blah"]))

Bem, isso tudo depende do seu estilo ... Se você gosta de ver o final, quando você não estará modificando a variável, em seguida, usá-lo. Se você não gosta de vê-lo ... em seguida, deixá-lo fora.

Eu pessoalmente gosto tão pouco detalhamento possível, por isso tendem a evitar o uso de palavras-chave adicionais que não são realmente necessárias.

Eu prefiro linguagens dinâmicas, porém, por isso é provavelmente nenhuma surpresa que eu gosto de verbosidade evitar.

Então, eu diria que apenas escolher a direção que você está inclinando-se para e apenas ir com ele (seja qual for o caso, tentar ser coerente).


Como uma nota lateral, eu tenho trabalhado em projetos que tanto o uso e não usar tal padrão, e eu não vi nenhuma diferença na quantidade de bugs ou erros ... Eu não acho que é um padrão que será extremamente melhorar sua contagem de erro ou qualquer coisa, mas novamente é estilo, e se você gosta de expressar a intenção de que você não vai modificá-lo, então vá em frente e usá-lo.

É útil em parâmetros para a mudança evite o valor do parâmetro por acidente e introduzir um bug sutil. Eu uso para ignorar esta recomendação, mas depois de passar cerca de 4 horas. em um método horrível (com centenas de linhas de código e várias Fors, ifs aninhados e todos os tipos de más práticas) eu recomendo que você fazê-lo.

 public int processSomethingCritical( final int x, final int y ){
 // hundreds of lines here 
     // for loop here...
         int x2 = 0;
        x++; // bug aarrgg...
 // hundreds of lines there
 // if( x == 0 ) { ...

 }

É claro que em um mundo perfeito isso não acontecer, mas .. bem .. às vezes você tem que apoiar os outros código. :(

Se você estiver escrevendo um aplicativo que alguém vai ter que ler o código depois de, digamos, 1 ano, então sim, use final sobre variável que não deve ser modificado o tempo todo. Ao fazer isso, seu código será mais "auto-documentado" e você também reduzir a chance para outros desenvolvedores de fazer coisas bobas como o uso de uma constante local como uma variável temporária local.

Se você está escrevendo algum código descartável, então, nah, não se preocupam em identificar todos a constante e torná-los final.

Vou usar final como tanto quanto eu puder. Se o fizer, bandeira vontade se você acidentalmente alterar o campo. Eu também definir os parâmetros de método para final. Se o fizer, eu peguei vários bug de código que assumiram quando eles tentam 'set' um parâmetro esquecendo Java passa por valor.

Não está claro a partir da questão de saber se isso é óbvio, mas fazer uma final parâmetro do método afeta somente o corpo do método. Ele não transmitir alguma informação interessante sobre as intenções do método para o invocador. O objecto que está sendo passado ainda pode ser mutado dentro do método (finais não são consts), e o âmbito da variável está dentro do método.

Para responder à sua pergunta precisa, eu não me incomodaria de fazer uma instância ou variável local (incluindo parâmetros do método) finais a menos que o código exige-se (por exemplo, a variável é referenciada a partir de uma classe interna), ou para esclarecer alguma lógica realmente complicado .

Para variáveis ??de instância, eu iria fazê-los final, se eles são logicamente constantes.

Existem muitos usos para o final variável. Aqui estão apenas alguns

final Constantes

 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }

Isto pode ser usado, em seguida, para outras partes de seus códigos, ou acessados ??por outras classes, dessa forma, se você nunca iria alterar o valor que você não tem que mudá-los um por um.

Variáveis ??finais

public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}

Nesta classe, você constrói uma última variável com escopo que adiciona um prefixo para o environmentKey parâmetro. Neste caso, a última variável é final apenas dentro do escopo de execução, que é diferente em cada execução do método. Cada vez que o método é inserido, o final é reconstruído. Assim que ele é construído, não pode ser alterado durante o escopo da execução do método. Isso permite que você corrigir uma variável em um método para a duração do método. veja abaixo:

public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}

final Constantes

public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}

Estes são especialmente úteis quando você tem realmente longas filas de códigos, e ele irá gerar erro do compilador que você não correr para a lógica de erro / negócio quando alguém acidentalmente muda variáveis ??que não deve ser alterado.

Finais coleções

caso diferente quando estamos a falar de coleções, você precisará configurá-los como um unmodifiable.

 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }

Caso contrário, se você não configurá-lo como unmodifiable:

Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler

Classes finais e Métodos finais não pode ser estendido ou substituído, respectivamente.

EDIT: para abordar as FINAL CLASSE problema em relação Encapsulamento:

Há duas maneiras de fazer uma final classe. A primeira é usar a palavra-chave final na declaração da classe:

public final class SomeClass {
  //  . . . Class contents
}

A segunda maneira de fazer uma última classe é declarar todos os seus construtores como privada:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

marcando-final, poupa o trabalho se descobrir que é real a final, para demonstrar olhada nesta classe de teste. olha público à primeira vista.

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

Infelizmente, uma vez que o único construtor da classe é particular, é impossível estender essa classe. No caso da classe de teste, não há razão para que a classe deve ser final. A classe Test é um bom exemplo de como implícita classes final pode causar problemas.

Portanto, você deve marcá-lo final, quando você faz implicitamente uma final classe, tornando-a do construtor privado.

Um pouco de um trade-off como você menciona, mas eu prefiro o uso explícito de algo sobre o uso implícito. Isso ajudará a remover alguma ambiguidade para futuros mantenedores de código - mesmo que seja apenas você.

Se você tem classes internas (anônimos), e as necessidades do método a variável de acesso do método contendo, você precisa ter essa variável como final.

Além disso, o que você disse é certo.

Use palavras-chave final para uma variável se você estiver fazendo essa variável como immutable

Ao declarar a variável como final, ela ajuda os desenvolvedores para descartar possíveis problemas de modificação de variáveis ??no ambiente altamente multi-thread.

Com java 8 lançamento, temos mais um conceito chamado " effectively final variable ". Uma variável não-final pode heave como variável final.

variáveis ??locais referenciados a partir de uma expressão lambda deve ser final ou efetivamente final

A variável é considerada eficaz final se não for modificado após a inicialização no bloco local. Isto significa que você pode agora usar a variável local sem palavra-chave final dentro de uma classe ou lambda expressão anônima, desde que deve ser efetivamente final.

Até Java 7, você não pode usar uma variável local não final dentro de uma classe anônima, mas a partir de Java 8 você pode

Tenha um olhar neste artigo

A resposta muito simples, temos 3 casos com final com variáveis, Final com métodos && final com aulas ..

1.Final com variável: u não posso atribuir essa variável mais de uma vez ..

2.Final com métodos: u não posso substituir esse método ..

3.Final com classes: u não posso estender qualquer classe final

Em primeiro lugar, a palavra-chave final é usado para fazer uma constante variável. meios constantes isso não muda. Por exemplo:

final int CM_PER_INCH = 2.54;

Você iria declarar a variável final por causa de um centímetro por polegada não muda.

Se você tentar substituir um valor final, a variável é o que foi declarado em primeiro lugar. Por exemplo:

final String helloworld = "Hello World";
helloworld = "A String"; //helloworld still equals "Hello World"

Há um erro de compilação que é algo como:

local variable is accessed from inner class, must be declared final

Se a variável não pode ser declarado como final ou se você não quer declará-la tentativa final, o seguinte:

final String[] helloworld = new String[1];
helloworld[0] = "Hello World!";
System.out.println(helloworld[0]);
helloworld[0] = "A String";
System.out.println(helloworld[0]);

Isto irá imprimir:

Hello World!
A String
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top