Java Code Conventions e suas declarações! Encara?

Olá pessoal,

Mais uma vez a Java Code Conventions me mostra um caminho que parece ser aquele caminho do inferno… :twisted: mas tenho certeza que, como na última vez que questionei determinado ponto da JCC, vou já já descobrir que esse caminho para o inferno é na verdade o caminho para os céus! :-o

Eis a questão:

[quote][size=16]6 - Declarations[/size]

[size=14]6.2 Placement[/size]
[size=12]Put declarations only at the beginning of blocks. (A block is any code surrounded by curly braces “{” and “}”.) Don’t wait to declare variables until their first use; it can confuse the unwary programmer and hamper code portability within the scope.[/size]

[code]void MyMethod() {
int int1; // beginning of method block

if (condition) {
    int int2; // beginning of "if" block
    ...
}

}[/code]
[size=14]6.3 Initialization[/size]
[size=12]Try to initialize local variables where they’re declared. The only reason not to initialize a variable where it’s declared is if the initial value depends on some computation occurring first.[/size][/quote]

:arrow: É uma coisa que não consigo compreender: imagine que você está desenvolvendo formulários com o Swing e este formulário tem mais de 60 JTextField, 10 JComboBox, 15 JButtons, 7 JCheckBox e X etc’s…
Se pela convenção devo declarar essas variáveis locais logo no início do método, quando estiver inicializando as mesmas ou alterando as configurações de alguma delas, lá no meio do código deste mesmo método, sou obrigado a ir lá para o alto, verificar qual é o nome da variável, voltar lá para o meio do código e então fazer a modificação necessária. Não seria mais conveniente ir declarando os componentes conforme vou adicionando eles ao JPanel do formulário ao invés de ter que ficar indo e voltando toda hora no código, como manda a convenção? Não é mais legível ir declarando aos poucos, ou seja, em seu primeiro uso? E quanto a portabilidade, a mesma coisa: quanto mais próximas estiverem as declarações das váriaveis de suas modificações, mais portável fica determinados trechos do código, não?

Para ilustrar:

[code]
public void criarForm() {
JPanel p = new JPanel();

    p.add(new JLabel("Primeiro Nome:"));
    JTextField nome = new JTextField(50);
    p.add(nome)
    
    p.add(new JLabel("Sobrenome:"));
    JTextField sobrenome = new JTextField(100);
    p.add(sobrenome);
  	
    p.add(new JLabel("Data Nascimento:"));
    JFormattedTextField dataNasc = new JFormattedTextField("##/##/####"));
    p.add(dataNasc);

    ...
}

[/code] Veja como o código é estupidamente legível. Tenho a variável do painel declarado logo de cara, como manda Code Conventions. Porém, os JTextField`s e JFormattedTextField declaro no seu primeiro uso. No exemplo temos três componentes sendo adicionados. Agora imaginem se fossem 8356 componentes sendo que todas as declarações de variáveis estariam logo alí em cima junto com a declaração do painel. Quando estiver lá na linha 6340 como vou me lembrar o nome da variável declarada? Vou ficar fazendo um vai e volta no código de cima para baixo sem parar, o que é horrivel tanto para legibilidade quanto para portabilidade futura deste código.

:idea: AGORA DEIXO EM ABERTO A OPINIÃO DOS SENHORES: ESTOU COM A RAZÃO OU DEVO IR MESMO PULAR O CARNAVAL? :roll:
Não deixe de opinar, pode parecer uma baita besteira, mas é importante, ainda mais nos dias de hoje que os códigos parecem ser escrito seguindo a JAVA CODE “INCONVENTIONS”!
Forte abraço leitor.

1 curtida

Você está certo. Alguns livros realmente importantes sobre construção de software, como Code Complete e Refactoring dizem para declarar variáveis no ponto mais próximo possível onde for usá-las.

Isso ajuda a identificar blocos de código e facilita para que ferramentas separem métodos mais facilmente. Não sei em que ponto as declarações no início do método podem ajudar um programador descuidado, como a frase indica. Geralmente, afastar a declaração gera código sujeito a erros, e mais difícil de ler. O curioso é que esse é um item da especificação que não vemos sendo seguido em diversos projetos open source por aí.

1 curtida

Eu concordo com a regra da JCC. No caso do seu exemplo, tem o problema de repetição de código. Podíamos mudar pra algo do tipo:

[code]public void criarForm() {
JPanel p = new JPanel();

adicionarCampoComLabel(p, 50, "Primeiro Nome:");
adicionarCampoComLabel(p, 100, "Sobrenome:");
adicionarCampoFormatadoComLabel(p, "##/##/####", "Data Nascimento:");

...  

}

public void adicionarCampoComLabel(JPanel p, int tamanhoCampo, String textoLabel) {
JTextField campo = new JTextField(tamanhoCampo);
p.add(new JLabel(textoLabel);
p.add(campo);
}

public void adicionarCampoFormatadoComLabel(JPanel p, String formato, String textoLabel) {
JFormattedTextField campo = new JFormattedTextField(formato);
p.add(new JLabel(textoLabel);
p.add(campo );
}
[/code]

Não vou dizer que essa seja a melhor solução, mas é uma que eu vejo pra não desrespeitar essa regra da JCC. Se o método tem MUITAS variáveis, provavelmente dê para dividí-lo em outros e evitar uma lista de 500 variáveis logo no começo ou 500 variáveis espalhadas pelo corpo do método (não sei o que é pior :roll: )

2 curtidas

Como o exemplo dele usa declaração no ponto mais próximo possível, seria bastante fácil rodar a opção "Refactoring->Extract Method", e eliminar a duplicação de código.
Essa refatoração é realmente traumática se você inicializar todas as suas variáveis só no início dos blocos.

[quote=ViniGodoy]Como o exemplo dele usa declaração no ponto mais próximo possível, seria bastante fácil rodar a opção "Refactoring->Extract Method", e eliminar a duplicação de código.
Essa refatoração é realmente traumática se você inicializar todas as suas variáveis só no início dos blocos.[/quote]

Concordo. Nesse caso, você desrespeita o item da especificação pra fazer um Refactoring e então seguí-lo. :stuck_out_tongue:

Legal senhores, bem bacana as explicações, parabéns. Obrigado.

Declarar tudo no começo do método é coisa que é obrigatória em C, mas não é em C++ ou em Java, devido principalmente ao princípio de máxima localidade. Quanto mais perto do uso é a declaração de algo, menor será seu escopo e menos tempo uma variável ficará potencialmente ocupando recursos .

Uma coisa que odeio em C é ter de fazer isto:

int main (int argc, char *argv[]) {
    int i; /* declaração longe do uso */
    ....
    ....
    for (i = 0; i < argc, ++i) {
        printf ("%s ", argv[i]);
    }
}

onde a declaração da variável de índice está a quilômetros de distância do seu uso.

Felizmente, em C ainda é possível (mediante novo escopo) fazer declarações próximas ao seu uso, embora isso não pareça muito “C”). Por exemplo:

int main (int argc, char *argv[]) {
    ....
    ....
    if (x > 0) {
        int i; /* como está dentro de novo escopo, podemos usar uma declaração mais próxima ao uso */
        for (i = 0; i < argc, ++i) {
            printf ("%s ", argv[i]);
        }
    }
}

Uma coisa esquisita que existe em C++ mas não em Java é declarar variáveis dentro de um “if” ou “while” - em Java só dá para fazer isso dentro de um “for”:

    while (char *p = gets(line)) {
        cout << p << endl;
    }

Enquanto o equivalente em Java seria algo como:

    for (String linha = br.readLine(); linha != null; linha = br.readLine()) {
        System.out.println (linha);
    }
}