静态导入方法的好用例是什么?

时间:2009-01-07 15:46:02

标签: java static-import

刚刚得到评论评论我静态导入该方法并不是一个好主意。静态导入是来自DA类的方法,该类主要使用静态方法。因此,在业务逻辑的中间,我有一个似乎属于当前类的da活动:

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

审稿人并不热衷于我改变代码而我没有,但我确实同意他的观点。给出非静态导入的一个原因是,在定义方法的地方很混乱,它不在当前类中而不在任何超类中,所以它也有一段时间来识别它的定义(基于Web的审查系统没有可点击的IDE之类的链接:-)我真的不认为这很重要,静态导入仍然很新,我们很快就会习惯定位它们。

但另一个原因,我同意的是,一个不合格的方法调用似乎属于当前对象,不应该跳转上下文。但如果确实属于它,那么扩展超级类是有意义的。

那么,当 时,它对静态导入方法有意义吗?你什么时候做的?您是否喜欢不合格的电话看起来的方式?

编辑:流行的观点似乎是静态导入方法,如果没有人会将它们混淆为当前类的方法。例如,java.lang.Math和java.awt.Color中的方法。但是如果abs和getAlpha不模糊,我不明白为什么readEmployee是。在许多编程选择中,我认为这也是个人偏好的事情。

感谢您的回复,我正在结束这个问题。

16 个答案:

答案 0 :(得分:134)

这是Sun发布该功能时的指南(重点是原创):

  

那么什么时候应该使用静态导入? 非常谨慎!只有在您想要声明常量的本地副本或滥用继承(Constant Interface Antipattern)时才使用它。 ...如果过度使用静态导入功能,它可能会使您的程序无法读取且无法维护,并使用您导入的所有静态成员污染其命名空间。您的代码的读者(包括您,在您编写它几个月后)将不知道静态成员来自哪个类。从类中导入所有静态成员对可读性特别有害;如果您只需要一个或两个成员,请单独导入。

https://docs.oracle.com/javase/8/docs/technotes/guides/language/static-import.html

我想特别提到两个部分:

  • 当您试图“滥用继承”时,请使用静态导入 。在这种情况下,您是否想要使用BusinessObject extend some.package.DA?如果是这样,静态导入可能是一种更清晰的处理方式。如果你从来没有想过要扩展some.package.DA,那么这可能是对静态导入的不良使用。输入时不要仅用于保存几个字符。
  • 导入个别成员。说出import static some.package.DA.save而不是DA.*。这样可以更容易地找到导入方法的来源。

就我个人而言,我很少使用这种语言功能非常,而且几乎总是只使用常量或枚举,从不使用方法。对我来说,权衡几乎是不值得的。

答案 1 :(得分:60)

静态导入的另一个合理用途是使用JUnit 4.在JUnit的早期版本中,assertEqualsfail之类的方法是继承的,因为测试类扩展了junit.framework.TestCase

// old way
import junit.framework.TestCase;

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

在JUnit 4中,测试类不再需要扩展TestCase,而是可以使用注释。然后,您可以从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以这种方式使用它。

答案 2 :(得分:25)

Effective Java, Second Edition,在第19项的末尾指出,如果您发现自己严重使用实用程序类中的常量,则可以使用静态导入。我认为这个原则适用于常量和方法的静态导入。

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();
    }
}

这有利有弊。它使代码更具可读性,代价是丢失一些关于定义方法的直接信息。但是,一个好的IDE会让你进入定义,所以这不是一个问题。

你应该谨慎地使用它,并且只有当你发现自己多次使用导入文件中的东西时才会这样做。

编辑更新为更具体的方法,因为这就是这个问题所指的内容。无论导入的是什么(常数或方法),该原则都适用。

答案 3 :(得分:11)

我同意从可读性角度来看它们可能存在问题,应该谨慎使用。但是当使用常见的静态方法时,它们实际上可以提高可读性。例如,在JUnit测试类中,像assertEquals这样的方法显而易见。同样适用于来自java.lang.Math的方法。

答案 4 :(得分:10)

我经常将它用于Color。

static import java.awt.Color.*;

颜色不太可能与其他东西混淆。

答案 5 :(得分:6)

我认为在使用像ArraysAssertions这样的utils类时,静态导入对于删除多余的类名非常有用。

不确定为什么,但罗斯跳过了documentation he is referencing中提到的最后一句话。

  

通过适当使用,静态导入可以通过删除重复类名的样板来使程序更具可读性。

基本上从此博客中复制:https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

例如:

测试中的断言

这是我认为我们都同意的最明显的案例

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

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

实用工具类和枚举

在使用utils类使代码更易于阅读时,可以在很多情况下删除类名

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

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

java.time包有一些应该使用的情况

// 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));

何时不使用

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

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

答案 6 :(得分:2)

由于您刚才提到的问题,静态导入是我从未使用过并且不打算使用的Java的唯一“新”功能。

答案 7 :(得分:2)

在将数学繁重的代码从C / C ++移植到java时,我使用'import static java.lang.Math。*'。数学方法映射1到1,并且在没有类名限定的情况下更容易区分移植的代码。

答案 8 :(得分:2)

我建议在使用带有Java的OpenGL时使用静态导入,这是一个使用案例属于&#34;大量使用来自实用程序类的常量&#34; 类别

考虑一下

import static android.opengl.GLES20.*;

允许您移植原始C代码并编写可读的内容,例如:

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

而不是普遍的普遍丑陋:

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

答案 9 :(得分:1)

它们有助于减少措辞,特别是在调用了大量导入方法的情况下,本地方法和导入方法之间的区别很明显。

一个例子:涉及对java.lang.Math的多次引用的代码

另一个:An XML builder class在每个引用前面加上类名会隐藏正在构建的结构

答案 10 :(得分:1)

我认为静态导入对于getLS样式的NLS来说很简洁。

import static mypackage.TranslatorUtil._;

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

这两者都将字符串标记为必须提取的字符串,并提供一种简单而干净的方式来替换字符串及其翻译。

答案 11 :(得分:1)

IMO静态导入是一个非常好的功能。绝对正确的是,严重依赖静态导入会使代码难以理解,并且难以理解静态方法或属性属于哪个类。但是,根据我的经验,它成为一个可用的功能,尤其是在设计提供一些静态方法和属性的Util类时。通过建立代码标准可以规避每当提供静态导入时产生的歧义。根据我在公司内部的经验,这种方法是可以接受的,并使代码更清晰,更易于理解。我最好在前静态方法和静态属性(以某种方式从C中采用)中插入_字符。显然,这种方法违反了Java的命名标准,但它提供了代码的清晰度。例如,如果我们有一个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){

    }
}

在这种情况下,静态导入提供了清晰度,代码结构对我来说更优雅:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

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

有人可以告诉哪个方法或属性来自静态导入​​,它隐藏了它所属的类的信息。我不建议对作为模块不可分割的一部分的类使用静态导入,并提供静态和非静态方法,因为在这些情况下,知道哪个类提供某些静态功能很重要。

答案 12 :(得分:1)

谈论单元测试:大多数人使用静态导入来处理模拟框架提供的各种静态方法,例如when()verify()

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

当然,当使用唯一断言时你应该使用`assertThat()它可以方便地静态导入所需的hamcrest匹配器,如:

import static org.hamcrest.Matchers.*;

答案 13 :(得分:1)

我发现使用Utility类时这非常方便。

例如,代替使用:if(CollectionUtils.isNotEmpty(col))

我可以代替:

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

当我在代码中多次使用此实用程序时,哪个IMO会提高代码的可读性。

答案 14 :(得分:0)

您需要在以下时间使用它们:

  • 您希望使用带有枚举值的switch语句
  • 您希望使代码难以理解

答案 15 :(得分:-5)

我尽可能地使用它们。我有IntelliJ设置提醒我,如果我忘了。我认为它看起来比完全合格的包名更干净。