Em Java, o uso do `import static` ajuda ou prejudica a legibilidade do código?

Muito se fala sobre a verbosidade de Java, mas tirando proveito do import static é possível escrever código bem limpo.

Considere o código abaixo:

import static java.lang.System.out;
import static java.util.List.of;
import static java.util.stream.Collectors.groupingBy;

enum Role { MANAGER, DEVELOPER }

class Employee {
  public final String name;
  public final Role role;

  Employee(final String name, final Role role) {
    this.name = name;
    this.role = role;
  }

  @Override
  public String toString() {
    return String.format("%s (%s)", this.name, this.role);
  }
}

public class Main {
  public static void main(String[] args) {
    var persons = of(
        new Employee("João", Role.MANAGER),
        new Employee("Paulo", Role.DEVELOPER),
        new Employee("Maria", Role.MANAGER),
        new Employee("Marta", Role.DEVELOPER)
    );

    persons
        .stream()
        .collect(groupingBy(e -> e.role))
        .forEach((role, list) -> out.printf("List of %s: %s\n", role, list));
  }
}

E aqui um trecho sem o import static:

import java.util.List;
import java.util.stream.Collectors;

/* ... */

persons
    .stream()
    .collect(Collectors.groupingBy(e -> e.role))
    .forEach((role, list) -> System.out.printf("List of %s: %s\n", role, list));

É um exemplo bobo, mas acredito que pode fazer maior diferença em situações mais complexas.

Então, com base na sua experiência, fica a pergunta do titulo.

Acrescento o seguinte:

  1. Não estou considerando o uso static-import-on-demand (exemplo abaixo), que acho que pode prejudicar o entendimento do código
// Prática ruim
import static java.lang.System.*;
import static java.util.List.*;
import static java.util.stream.Collectors.*;
  1. Além da sua opinião pessoal, o que o code style da sua empresa diz?

Creio que um dos problemas do static é o consumo de memória, ele não é despejado, fica sempre ali. Em um projeto pequeno não se percebe a diferença, mas num grande, que não pode ser fechado, acaba prejudicando a memória do Pc.

Em questão de code style, o static facilita muito, fica bem mais limpo e mais legível.

O que a Oracle diz sobre isso:

The static import declaration is analogous to the normal import declaration. Where the normal import declaration imports classes from packages, allowing them to be used without package qualification, the static import declaration imports static members from classes, allowing them to be used without class qualification.

So when should you use static import? Very sparingly! Only use it when you’d otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Readers of your code (including you, a few months after you wrote it) will not know which class a static member comes from. Importing all of the static members from a class can be particularly harmful to readability; if you need only one or two members, import them individually. Used appropriately, static import can make your program more readable, by removing the boilerplate of repetition of class names.

Fonte: docs.oracle.com - Static Import

1 curtida

@rodriguesabner quando vc fala da questão do consumo de memória, vc se refere a quando usamos membros estáticos para alocar recursos, não é?

Minha questão é sobre importar métodos estáticos de certas classes. O import static por si só não influencia na memória ou algo assim como podemos ler no link que o colega compartilhou.

@Jothar_Aleksander obrigado por compartilhar o link. Li o texto completo e, basicamente ele reflete a minha opinião quando diz que:

  1. Deve ser usado com moderação.
  2. Quando usado com o “*” pode prejudicar a legibilidade
  3. Usado apropriadamente pode tornar o programa mais legível.

Eu só fico na dúvida sobre o que é considerado usar “com moderação”.

Sei que quando trabalhando com JUnit é comum importar os métodos de Assertations como static.

E pra mim, quando trabalhando com streams, faz sentido importar os métodos de Collectors como static.

Mas independente do que a Oracle diz, o que vc pensa sobre o uso? Faz sentido usar? Vc usaria? Se vc trabalha com a linguagem, o que sua empresa, em particular, diz ou diria sobre escrever código assim?

Nunca vi um projeto Java dessa forma, então eu não ia querer ser o diferente. O Eclipse coloca automaticamente os imports dessa forma? Caso contrário já descartaria na hora.

Java é improdutivo e verboso por natureza, mas quem quiser pode usar gambiarras como o lombok pra melhorar esse lado. E pra quem conhece linguagens melhores, nem vale usar Java para novos projetos.

1 curtida

Lombok é gambiarra? Por quê?

Eu pessoalmente gosto muito dele, uso praticamente em todo projeto.

2 curtidas

Pra quem já está acostumado a usar o Java, a verbosidade não é um problema em si. As coisas acabam acontecendo automaticamente. Mas se a pessoa for usar um C# ou C++ nao muda muita coisa. Fora que melhor parte de usar Java, é que vc consegue usar qualquer outra linguagem sem muita dor de cabeça

1 curtida

Pra quem só vive no java concordo. Mas pra quem passa por C# ou Kotlin a diferença é bem clara em serem mais limpas e expressivas, sem precisar de gambiarras.

Ia fazer a mesma pergunta. Inclusive é possível que muito em breve ele seja pro Java o que o Hibernate foi pra Spec JEE.

É um ótimo recurso pra cobrir a deficiência da linguagem java, nao tem problema em usar, mas nao precisaria dessa gambiarra se a linguagem java fosse menos verbosa. Expressivamente vai escrever .getAlgumaCoisa, mas no código visível não tem, sendo necessário até instalar recurso a parte pra IDE nao se perder.

Vocês sabem que expressividade e elegibilidade tem muito a ver com você ler e entender o que está lndo. As vezes menos caracteres em uma frase e menos linhas de código não querem dizer mais elegível.

Assim como em um texto em português, legível é aquilo que você consegue ler sem ter que repetir a leitura pra conseguir entender.

Seu código fonte é a mesma coisa, quanto mais próximo você consegue ler o código e não precisar voltar nele para entendê-lo, melhor.

No final das contas isso depende muito mais de quem está escrevendo e lendo do que dos recursos da linguagem em si.

No caso dos import static eu não me importo de usar se seu projeto estiver bem OO. Em caso de códigos legados macarrônicos eu prefiro evitar, pois a possibilidade da classe fazer mais de uma coisa e eu ter que ficar indo o tempo todo na importação pra saber a origem dos static é muito grande.

2 curtidas

Concordo. Por isso Java é bom e por isso Cobol foi tão bom. Quem programa e tem que dar manutenção entende.

E sobre lombok fazer uso de Anotações, elas fazem parte da linguagem Java, e se foi usado para escrever menos get e set , beleza, isso não é gambiarra e sim um recurso que a linguagem oferece para quem queira fazer uso.

Sim, em relação ao Kotlin eu até concordo, mas acho o C# verboso também. O php é verboso também, mas eu concordo com o Adriano, ou talvez seja falta de costume mesmo, mas em algumas linguagens como o React/ RNative… tem coisas que você não sabe de onde veio, pra onde vai, só prestando muita atenção no código que você consegue compreender, diferente do Java, que é como se estivesse escrevendo um texto

1 curtida

Existem linguagens que escrever um Ola mundo é uma belezinha, mas quando a coisa aumenta, dá dó da gente que programa e tem que arruma.
Quantas veze em Java precisei ler o fonte do javaFX, do Swing e até mesmo das classes bases do java. Falo com segurança em relação a isso, diferente de muitas linguagens por ai de pouca verbosidade. Tem uma hora que quem programa vai rezar pra ser em Java.

1 curtida

Em relação a import static, não acho que prejudica a legibilidade do codigo. Mas prefiro não usar tanto.

Mas você sabe que a linguagem que omite no compilado está incluindo certo? Então o que o Lombok faz é a mesma coisa, apenas não é nativo da linguagem (ainda, acredito eu).

C# ainda é tipado, ou seja, ainda tem alguma verbosidade associada por default, mas acredite, eles conseguiram sim fazer ser menos verboso que Java.

Eu gosto de PHP, mas até hoje não entendo porque eles definiram o “->” para acessar atributos :frowning:
Porém acho a ideia de definir as variáveis com um $ muito boa, me agrada aos olhos.

Total, depois que você acostuma com um linguagem, fica mais fácil você começar a ver ela brilhando. Foi meu caso com C# e Python.

De novo, questão de costume. Você não enxerga porque ainda não aprendeu, aí tudo parece meio mágico.

De novo, depende… :smiley: Você está acostumado, aí parece fluente, mas com certeza muita coisa que você faz hoje você gostaria de retirar da linguagem, ou fazer de uma forma diferente que deixaria bem “menos sujo” digamos assim.

Sim, no geral as APIs do Java tendem a ser bem escritas, a bosta mesmo é quando o cara usa os 200 padrões do livro do GOF pra escrever algo que poderia ser resolvido em 2 métodos pequenos. Mas aí já não é mais um problema da linguagem e sim de overengineering.

Valeu´pela discussão saudável turma.

1 curtida

Vou responder de acordo com minha experiência após utilizar ele em um projeto há cerca de 2 anos.

A gambiarra começa por ele ser um processador de anotações que é executado em tempo de compilação, o que permite que você escreva código semanticamente errado que não seria compilável pelo javac.

Por exemplo, você vai ter uma classe A somente com atributos, sem getters e setters, mas em outra B você cria objetos do tipo A e invoca os getters e setters que não existem no fonte.

O argumento para utilizá-lo é a redução de escrita de código comum (boiler plate code), que se resume basicamente à:

  • construtores;

  • getters e setters;

  • equals e hashcode.

Acontece que em grandes projetos profissionais, os construtores, getters, setters, equals e hashcode são códigos que raramente sofrem manutenção, geralmente após criados nunca mais são modificados, então o Lombok acaba não aumentando a produtividade, como muitos acham que aumenta.

Até porque esses códigos são facilmente gerados pelas IDEs através de teclas de atalho ou menus pop-up.

Acredito que ficaria interessante se futuramente o Java incluísse uma palavra reservada property na linguagem, aí teríamos algo parecido com o @Getter e @Setter do Lombok.

Do meu ponto de vista, o que de fato aumenta a produtividade e facilidade de manutenção é a adoção de boas práticas de desenvolvimento (SOLID principles e Design Patterns por exemplo), mas isso é assunto pra outro tópico.

Do meu ponto de vista, há formas melhores de se trabalhar, por exemplo:

  • construtores: podem ser substituídos por factory methods ou implementar o padrão builder;

  • getters e setters: avaliar a real necessidade, se os getters e setters servem somente para acessar atributos private sem nenhuma lógica ou validação, então eles não são necessários, basta tornar os atributos public;

  • equals e hashcode: podem ser substituídos por implementações de fácil manutenção com o padrão strategy.

5 curtidas

Dificilmente eu uso o import static. Nas poucas vezes que utilizei, foi em testes unitários e utilizando o Mockito.
Se torna mais ou menos legível? Ao meu ver, se você não está acostumado com a linguagem e não usa esse recurso com frequência, acaba tendo dificuldades, sim. De repente você encontra uma invocação a um método que não existe nem na classe, nem na superclasse (quando há herança). E aí?
Aí que você precisará começar uma busca e encontrar razões que levem a esse uso.

Acredito que java possua problemas maiores e mais específicos, como manter-se engessado devido a retrocompatibilidade.

Lombok: genial. Creio que, em algum momento, aquilo será o padrão:

@Getter @Setter
private String nome;

Minha dificuldade com o PHP foi que eu estudei orientação a objetos voltada para o java. Quando chegava no PHP (4 e 5) tinha problemas que eu achava absurdo não serem resolvidos, como a necessidade de criar um

__constructor(){}

E o destructor.
Além, obviamente, do famigerado ->.

Enfim, também acredito na questão de quanto você está familiarizado com esta ou aquela linguagem.

2 curtidas