web-dev-qa-db-fra.com

Quel est un bon cas d'utilisation pour l'importation statique de méthodes?

Je viens de recevoir un commentaire indiquant que mon importation statique de la méthode n’était pas une bonne idée. L'importation statique était une méthode d'une classe DA, qui a principalement des méthodes statiques. Donc, au milieu de la logique métier, j'avais une activité qui semblait appartenir à la classe actuelle:

import static some.package.DA.*;
class BusinessObject {
  void someMethod() {
    ....
    save(this);
  }
} 

Le critique ne souhaitait pas que je modifie le code et je ne l’ai pas fait, mais je suis plutôt d’accord avec lui. Une des raisons invoquées pour ne pas importer de données statiques était que la méthode était définie comme une source de confusion. Elle ne figurait ni dans la classe actuelle ni dans une super-classe. Il était donc temps d'identifier sa définition (le système de révision basé sur le Web n'est pas cliquable). Des liens tels que IDE :-) Je ne pense pas que ce soit important, les importations statiques sont encore assez nouvelles et nous allons bientôt tous nous habituer à les localiser.

Mais l’autre raison, avec laquelle je suis d’accord, est qu’un appel de méthode non qualifié semble appartenir à l’objet actuel et ne doit pas sauter de contexte. Mais si cela appartenait vraiment, il serait logique d’étendre cette super classe.

Alors, quand fait il est logique de recourir à des méthodes d’importation statique? Quand l'as-tu fait? Avez-vous/aimez-vous l'aspect des appels non qualifiés?

EDIT: L'opinion populaire semble être que les méthodes d'importation statique si personne ne va les confondre avec les méthodes de la classe actuelle. Par exemple, les méthodes de Java.lang.Math et Java.awt.Color. Mais si abs et getAlpha ne sont pas ambigus, je ne vois pas pourquoi readEmployee le serait. Comme dans beaucoup de choix de programmation, je pense que cela aussi est une question de préférence personnelle. 

Merci pour votre réponse les gars, je ferme la question.

114
Miserable Variable

C’est tiré du guide de Sun au moment de la publication de la fonctionnalité (en italique dans l’original):

Alors, quand devriez-vous utiliser l'importation statique? Très économiquement! Ne l'utilisez que lorsque vous seriez autrement tenté de déclarer des copies locales de constantes ou d'abuser de l'héritage (The Constant Interface Antipattern). ... Si vous abusez de la fonctionnalité d'importation statique, cela peut rendre votre programme illisible et non maintenable, en polluant son espace de noms avec tous les membres statiques que vous importez. Les lecteurs de votre code (y compris vous, quelques mois après l'avoir écrit) ne sauront pas de quelle classe provient un membre statique. Importer tous les membres statiques d'une classe peut être particulièrement nuisible à la lisibilité; si vous n'avez besoin que d'un ou deux membres, importez-les individuellement.

( https://docs.Oracle.com/javase/8/docs/technotes/guides/language/static-import.html )

Je souhaite appeler spécifiquement deux parties:

  • Utilisez des importations statiques uniquement lorsque vous avez été tenté "d'abuser de l'héritage". Dans ce cas, auriez-vous été tenté d'avoir BusinessObject extend some.package.DA? Si tel est le cas, les importations statiques peuvent constituer un moyen plus simple de gérer cela. Si vous n'auriez jamais rêvé d'étendre some.package.DA, il s'agit probablement d'une mauvaise utilisation des importations statiques. Ne l'utilisez pas uniquement pour sauvegarder quelques caractères lors de la frappe.
  • Importer des membres individuels. Dites import static some.package.DA.save au lieu de DA.*. Cela facilitera grandement la recherche de l’origine de cette méthode importée.

Personnellement, j'ai utilisé cette fonction de langage très rarement et presque toujours avec des constantes ou des énumérations, jamais avec des méthodes. Le compromis, pour moi, ne vaut presque jamais la peine.

137
Ross

JUnit 4 constitue une autre utilisation raisonnable des importations statiques. Dans les versions antérieures de JUnit, les méthodes telles que assertEquals et fail étaient héritées depuis la classe de test étendue junit.framework.TestCase.

// old way
import junit.framework.TestCase;

public class MyTestClass extends TestCase {
    public void myMethodTest() {
        assertEquals("foo", "bar");
    }
}

Dans JUnit 4, les classes de test n'ont plus besoin d'étendre TestCase et peuvent utiliser des annotations. Vous pouvez ensuite importer statiquement les méthodes d'assertion à partir de org.junit.Assert:

// new way
import static org.junit.Assert.assertEquals;

public class MyTestClass {
    @Test public void myMethodTest() {
        assertEquals("foo", "bar");
        // instead of
        Assert.assertEquals("foo", "bar");
    }
}

JUnit documents l’utiliser de cette façon.

60
Rob Hruska

Effective Java, Deuxième édition , à la fin de élément 19 indique que vous pouvez utiliser des importations statiques si vous vous trouvez lourdement en utilisant les constantes d'une classe d'utilitaires. Je pense que ce principe s’appliquerait aux importations statiques de constantes et de méthodes.

import static com.example.UtilityClassWithFrequentlyUsedMethods.myMethod;

public class MyClass {
    public void doSomething() {
        int foo= UtilityClassWithFrequentlyUsedMethods.myMethod();
        // can be written less verbosely as
        int bar = myMethod();
    }
}

Cela a des avantages et des inconvénients. Cela rend le code un peu plus lisible au risque de perdre des informations immédiates sur l'endroit où la méthode est définie. Cependant, un bon IDE vous laissera aller à la définition, donc ce n'est pas vraiment un problème.

Vous devez toujours l'utiliser avec parcimonie, et uniquement si vous utilisez fréquemment des éléments du fichier importé.

Edit: Mis à jour pour être plus spécifique aux méthodes, c'est ce à quoi cette question fait référence. Le principe s'applique indépendamment de ce qui est importé (constantes ou méthodes).

25
Rob Hruska

Je conviens qu’elles peuvent poser problème du point de vue de la lisibilité et doivent être utilisées avec parcimonie. Mais quand ils utilisent une méthode statique commune, ils peuvent réellement améliorer la lisibilité. Par exemple, dans une classe de test JUnit, les méthodes telles que assertEquals sont évidentes d'où elles viennent. De même pour les méthodes de Java.lang.Math.

11
Joel

Je l'utilise beaucoup pour Color.

static import Java.awt.Color.*;

Il est très peu probable que les couleurs soient confondues avec autre chose.

10
jjnguy

Je pense que l'importation statique est vraiment utile pour supprimer les noms de classe redondants lors de l'utilisation de classes utils telles que Arrays et Assertions.

Je ne sais pas pourquoi, mais Ross a ignoré la dernière phrase qui le mentionne dans la documentation à laquelle il fait référence .

Utilisée à bon escient, l’importation statique peut rendre votre programme plus lisible en supprimant le passe-partout de la répétition des noms de classe.

Fondamentalement copié de ce blog: https://medium.com/alphadev-iblyts/static-imports-are-great-but-underused-e805ba9b279f

Donc par exemple:

Assertions dans les tests

C’est le cas le plus évident sur lequel, je pense, nous sommes tous d’accord.

Assertions.assertThat(1).isEqualTo(2);

// Use static import instead
assertThat(1).isEqualTo(2);

Classes et enums utils

Le nom de classe peut être supprimé dans de nombreux cas lorsque des classes utils sont utilisées, ce qui facilite la lecture du code.

List<Integer> numbers = Arrays.asList(1, 2, 3);

// asList method name is enough information
List<Integer> numbers = asList(1, 2, 3);

Java.time a quelques cas où il devrait être utilisé

// Get next Friday from now, quite annoying to read
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.FRIDAY));

// More concise and easier to read
LocalDate.now().with(next(FRIDAY));

Exemple de quand ne pas utiliser

// Ok this is an Optional
Optional.of("hello world");

// I have no idea what this is 
of("hello world");
5
softarn

Je recommande l'utilisation de static import avec OpenGL avec Java, ce qui est un cas d'utilisation relevant de la catégorie "utilisation intensive de constantes à partir d'une classe d'utilitaires"

Considérer que

import static Android.opengl.GLES20.*;

vous permet de porter le code C d'origine et d'écrire quelque chose de lisible tel que:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(samplerUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuffer);
glVertexAttribPointer(vtxAttrib, 3, GL_FLOAT, false, 0, 0);

au lieu de cette laideur répandue commune:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(samplerUniform, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vtxBuffer);
GLES20.glVertexAttribPointer(vtxAttrib, 3, GLES20.GL_FLOAT, false, 0, 0);
2
Flint

Les importations statiques sont la seule "nouvelle" fonctionnalité de Java que je n’ai jamais utilisée et que je n’ai pas l’intention de faire, en raison des problèmes que vous venez de mentionner.

2
Bombe

J'utilise 'import statique Java.lang.Math. *' Lors du portage d'un code mathématique lourd de C/C++ vers Java. Les méthodes mathématiques mappent 1 à 1 et facilitent la différenciation du code porté sans qualification du nom de classe.

2
Fracdroid

Je pense que les importations statiques sont chouettes pour NLS dans le style gettext.

import static mypackage.TranslatorUtil._;

//...
System.out.println(_("Hello world."));

Ceci marque la chaîne comme une chaîne à extraire et fournit un moyen simple et propre de remplacer la chaîne par sa traduction.

1
Matthias Wuttke

J'ai trouvé cela très pratique lors de l'utilisation de classes utilitaires. 

Par exemple, au lieu d'utiliser: if(CollectionUtils.isNotEmpty(col)) 

Je peux plutôt:

import static org.Apache.commons.collections.CollectionUtils.isNotEmpty;
if(isNotEmpty(col))

Quelle OMI augmente la lisibilité du code lorsque j'utilise cet utilitaire plusieurs fois dans mon code.

1
Yeikel

L'importation statique IMO est une fonctionnalité intéressante. Il est absolument vrai que le recours important à l'importation statique rend le code illisible et rend difficile la compréhension de la classe à laquelle appartient une méthode ou un attribut statique. Cependant, selon mon expérience, cela devient une fonctionnalité utilisable, en particulier lors de la conception de classes Util qui fournissent des méthodes et des attributs statiques. L'ambiguïté qui se présente chaque fois que l'on fournit une importation statique peut être contournée en établissant des normes de code. D'après mon expérience au sein d'une entreprise, cette approche est acceptable et rend le code plus propre et facile à comprendre. De préférence, j'insère le caractère _ devant les méthodes statiques et les attributs statiques (en quelque sorte adopté de C) . Apparemment, cette approche viole les normes de nommage de Java, mais elle clarifie le code. Par exemple, si nous avons une classe AngleUtils:

public class AngleUtils {

    public static final float _ZERO = 0.0f;
    public static final float _PI   = 3.14f;

    public static float _angleDiff(float angle1, float angle2){

    }

    public static float _addAngle(float target, float dest){

    }
}

Dans ce cas, l'importation statique fournit la clarté et la structure du code me semble plus élégante:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

        float initialAngle = _ZERO;
        float angle1, angle2;
        _addAngle(angle1, angle2);
    }
}

Tout de suite, quelqu'un peut dire quelle méthode ou quel attribut provient d'une importation statique et cache les informations de la classe à laquelle elle appartient. Je ne suggère pas d'utiliser l'importation statique pour les classes faisant partie intégrante d'un module et fournissant des méthodes statiques et non statiques, car dans ce cas, il est important de savoir quelle classe fournit certaines fonctionnalités statiques. 

1
eldjon

Ils sont utiles pour réduire le verbiage, en particulier dans les cas où de nombreuses méthodes importées sont appelées, et la distinction entre méthodes locales et importées est claire.

Un exemple: code qui implique plusieurs références à Java.lang.Math

Une autre: Une classe de générateur XML où ajouter le nom de la classe à chaque référence masquerait la structure en construction

1
kdgregory

À propos des tests unitaires: la plupart des gens utilisent des importations statiques pour les différentes méthodes statiques fournies par mocking / framework, telles que when() ou verify().

import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Et bien sûr, lorsque vous utilisez le seul et unique assert, vous devriez utiliser `assertThat (), il est pratique d'importer de manière statique les correspondeurs de hamcrest requis, comme dans:

import static org.hamcrest.Matchers.*;
0
GhostCat

Vous devez les utiliser quand:

  • vous souhaitez utiliser une instruction switch avec des valeurs enum
  • vous souhaitez rendre votre code difficile à comprendre
0
davetron5000