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

38 respostas
wldomiciano

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?

38 Respostas

rodriguesabner

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.

Jothar_Aleksander

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

wldomiciano

@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?

javaflex

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.

FearX

Lombok é gambiarra? Por quê?

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

rodriguesabner

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

javaflex

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.

adriano_si

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

javaflex

É 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.

adriano_si

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.

j-menezes

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

j-menezes

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.

rodriguesabner

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

j-menezes

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.

j-menezes

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

adriano_si

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).

adriano_si

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.

staroski

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.

darlan_machado

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.

darlan_machado

Recentemente participei de um treinamento com arquitetos da Pivotal (Spring & Springboot).
Eles falaram sobre N coisas, incluindo kotlin, jpa x jdbc e arquitetura.
Quando o assunto foi lombok e feign, eles foram categóricos em dizer que ambos podem ser evitados. Mais que isso, devem ser evitados nos projetos em que não se façam necessários.
Além, claro, do eureka e outras ferramentas que comumente achamos ser a bala de prata.

rodriguesabner

Com certeza, no JDK 11 a gente já vê o uso do var, ao invés de String e int, como o Darlan falou, em questão de tempo isso será um padrão

@Getter @Setter
private String nome;

Por enquanto a gente só pode esperar os caras mudarem um pouco. Mas uma coisa que eu vi em Python e que achei bem legal, é que não é necessário declarar o nome da classe, fora tantas outras facilidades do python.

O Java tem muito potencial pra melhorar, acredito que com essas mudanças na Oracle, pode ser que haja algum avanço

wldomiciano

O Eclipse não sei, mas no IntelliJ vi que não coloca import static automaticamente.

Não conheço tanto o C#, mas pra quem concorda que ela é mais limpa que Java, de que forma ela é mais limpa?

Dependendo do código, vc só consegue dizer se é Java ou C# porque o método em C# costuma começar com letra maiúscula e as chaves costuma vir na linha de baixo.

C# tem o val, mas agora Java tem o var. Embora C# tenha bem mais recursos que Java, no quesito “código limpo” o único recurso que pesa mais são as properties, mas ainda sim é verboso.

O que vcs acham?

Sobre o Lombok, não o conhecia, mas gostei muito, tomara mesmo que se torne padrão ou que achei um jeito ainda melhor de implementar no core da linguagem.

Quer dizer que não impacta em nada na performance do runtime, mas, dependendo do tamanho do projeto, pode impactar no tempo de build, certo?

É mesmo, pode causar uma certa confusão a principio, mas se importar coisas estaticamente se torna-se um padrão na comunidade ou, pelo menos, dentro da empresa, pode se tornar mais natural eu acho.

Além disso, bastaria botar o mouse em cima do método pra IDE dizer da onde ele vem.

Bom, mas independente disso, pelo que todos disseram, seria mais seguro não usar este recurso na maioria das vezes. É melhor deixar pra usar apenas em bibliotecas ou frameworks que já padronizaram o uso como o Mockito ou o JUnit.

darlan_machado

Pense em um iniciante procurando um tutorial e dando de cara com a invocação a um método estático. Esse é o cenário que mais vejo. Até explicar que aquele método invocado é um método estático, declarado no import e blablablá, já criou-se uma confusão gigante.

Além disso, não é por que existe e funciona que deve-se usar. É o caso do goto. É uma palavra reservada do java, mas, você já usou? Recomenda?
DefaultTableModel para Swing, idem.

Concordo com o que o @staroski comentou: usar padrões de desenvolvimento como SOLID e clean code garante uma legibilidade maior ao código (o clean code parte do princípio que você escreve código legível, sem necessidade de comentários para explicar o que está fazendo. O pessoal da Pivotal foi bem enfático neste ponto: código bom é código legível).

P.S.:

Também não, ao menos até a versão 2019.2

javaflex

Concordo sobre C# ser mais verboso que Kotlin. Mas só quis dizer que Java é bem mais verboso que ambas.

Não entendi sobre chamar React de linguagem, mas dificilmente adotaria ferramentas desse tipo, pela característica que você citou. Achei uma zona pelo que vi até entao, mas por outro lado acredito que seja algo mais tranquilo pra cabeça dos mais jovens…

rodriguesabner

Não é uma linguagem, mas uma característica bem forte do JavaScript, assim como o Flutter.

Não que seja uma zona, mas pra que não está acostumado, como o Adriano comentou, pode ser algo extremamente estranho de se olhar, mas com o tempo acaba acostumando.

Querendo ou não, o JS tem se tornado muito forte de uns anos pra cá, em todos os aspectos, Web, Desktop, Mobile… É uma linguagem pra dar mais atenção

FearX

Um prato cheio esse tópico. Valeu pela contribuição de todos.

@staroski, a parte sobre os getters me chamaram atenção. Você acha que é uma boa solução mesmo isso? Atualmente crio todos meus atributos privados, colocando getter sempre.

adriano_si

Eu realmente queria entender mais isso aqui. Utilizamos Lombok em um Projeto legado com mais de 40 Services e muitas, mas muitas classes abaixo mesmo que utilizam Lombok e nenhuma delas tem um problema de achar um getter ou setter de outra. Você teve esse problema? Pode explicar o cenário que isso ocorreu?

A menos que você esteja falando de usar Java sem IDE. Alguém já tentou a sorte?

Quanto ao fato de executar em tempo de compilação, esse é o papel das anotações, anotações que são um recurso da linguagem, não vejo gambiarra.

Você pode dizer que anotações são gambiarras e que teriam um jeito “melhor” de fazer incluindo em tempo de execução ou escrita de código, mas chamar um recurso de uma linguagem de gambiarra porque tem uma forma que você acha melhor tem tópico pra discussão, porque claro que você pode estar certo, mas a decisão de implementar de uma forma em uma linguagem tão grande como é a de Java e na época que a decisão foi tomada ao incluir as annotations, ouso dizer que tem um motivo muito forte, sendo que foi tomada por vários players cruciais na época.

j-menezes

Gambiarra é quando se precisa pegar o valor do registrador puro em C/C++ e object Pascal.
E não quando se faz uso de Anotações em Java.

javaflex

Sei disso, mas eu só uso recursos do js que forem necessários pro projeto, nada que vá deixar a funcionalidade sem saber onde começa e termina.

staroski

Sim, funcionava na IDE, mas o problema foi que, sem ninguém saber, alguém havia configurado o projeto para usar Lombok e acabou refatorando algumas classes e criando classes novas com as annotations.

Aí, de repente, o ambiente de integração contínua começou a “explodir” sem ninguém entender, pois havia erros de compilação.

Resumindo, as builds do Jenkins, que eram mantidas por outra equipe, não estavam configuradas para incluir o annotation proccessor do Lombok durante a compilação, então isso gerou todo um estresse na equipe de desenvolvimento e na gerência do projeto.

Isso sim, vejo como gambiarra a característica de ele na verdade ser uma espécie de “estensão do compilador”, pois ele permite que um código esteja semanticamente errado do ponto de vista do javac.

Mas também também considero gambiarra por exemplo o bytecode instrumentation que o Hibernate e o AspectJ fazem no código.

O Lombok tem recursos interessantes? Tem!
Mas acredito que vai muito da maneira que cada um tem de desenvolver.
Acho super importante que em qualquer projeto, a adoção desse tipo de framework seja muito bem documentada, principalmente em projetos maiores onde possa haver diversas equipes trabalhando em diferentes frentes do desenvolvimento do produto.

:slight_smile:

staroski

Os getters e setters costumam ser simplesmente um accessor e mutator de um atributo private, sem nenhuma lógica ou validação por trás deles.

O próprio Robert Cecil Martin (autor do clean code), diz que os getters e setters expõe um atributo private como se ele fosse public.
Neste caso basta tornar o atributo public de uma vez, assim você escreve menos.

Acho que getters e setters só fazem sentido quando fazem parte de uma interface, pois uma interface define o comportamento de um objeto.
Então se você tem um set e um get em uma interface, você já está preparado que haverá polimorfismo e que pode haver alguma validação.

Falando de uma forma mais fácil de entender, eu vejo que os getters e setters podem fazer sentido em classes que vão representar um objeto polimórfico.

Mas são completamente desnecessários em classes que vão simplesmente representar uma estrutura de dados, um conjunto de informações ou um data transfer object.

adriano_si

Entendi. Ainda não considero gambiarra, mas consigo entender porque é considerado, levando em conta o discurso mais purista.

adriano_si

Sempre achei isso bizarro. Os tais objetos anêmicos. Não possuem comportamento e nem sequer se auto-validam, logo como apenas repositórios de dados onde se pode incluir o que quiser, é perda de tempo mesmo incluir métodos acessores.

javaflex

Sim, mas estou falando do que o programador lê, chamando um método .getAlgumaCoisa que não existe no seu código. Se for pra ter algo nativo, que façam direito implementando property, não essa coisa ai.

javaflex

Não é o único, o que posso lembrar no momento:

Métodos de extensao direto na instancia
Interpolacao de string
Tratamento de assincronicidade na própria linguagem
LINQ (streams do java que seria o mais próximo é um terror perto do LINQ do C#, java ainda peca muito no funcional)

staroski

Sim, por isso que eu, Ricardo Staroski, considero gambiarra. Risos.

Se fosse nativo da linguagem, eu não iria considerar.
Até o Object Pascal já tinha properties, o Java também poderia ter. Declarava o atributo como property e só escreveria explicitamente o getter e/ou setter, caso quisesse incluir alguma lógica ou validação…

wldomiciano

Isso ainda não vi como é no C#, mas legal, acredito que seja muito bom.

O LINQ é interessante, mas as streams do Java são bem legais também.

wldomiciano

Sobre o suporte do Eclipse ao import static, vi que se vc tem o seguinte código:

import java.util.List;

public class Main {
	public static void main(String... args) {
		System.out.println(List.of("a", "b", "c"));
	}
}

E clicar com o direito na palavra of, ir em SourceAdd Import ou pressionar Shift + Crtl + M ele adiciona a seguinte linha ao código:

import static java.util.List.of;

Já ajuda um pouco.

Criado 4 de setembro de 2019
Ultima resposta 10 de set. de 2019
Respostas 38
Participantes 9