159

Just got a review comment that my static import of the method was not a good idea. The static import was of a method from a DA class, which has mostly static methods. So in middle of the business logic I had a da activity that apparently seemed to belong to the current class:

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

The reviewer was not keen that I change the code and I didn't but I do kind of agree with him. One reason given for not static-importing was it was confusing where the method was defined, it wasn't in the current class and not in any superclass so it too some time to identify its definition (the web based review system does not have clickable links like IDE :-) I don't really think this matters, static-imports are still quite new and soon we will all get used to locating them.

But the other reason, the one I agree with, is that an unqualified method call seems to belong to current object and should not jump contexts. But if it really did belong, it would make sense to extend that super class.

So, when does it make sense to static import methods? When have you done it? Did/do you like the way the unqualified calls look?

EDIT: The popular opinion seems to be that static-import methods if nobody is going to confuse them as methods of the current class. For example methods from java.lang.Math and java.awt.Color. But if abs and getAlpha are not ambiguous I don't see why readEmployee is. As in lot of programming choices, I think this too is a personal preference thing.

Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
Miserable Variable
  • 28,432
  • 15
  • 72
  • 133

16 Answers16

167

This is from Sun's guide when they released the feature (emphasis in original):

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

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

There are two parts I want to call out specifically:

  • Use static imports only when you were tempted to "abuse inheritance". In this case, would you have been tempted to have BusinessObject extend some.package.DA? If so, static imports may be a cleaner way of handling this. If you never would have dreamed of extending some.package.DA, then this is probably a poor use of static imports. Don't use it just to save a few characters when typing.
  • Import individual members. Say import static some.package.DA.save instead of DA.*. That will make it much easier to find where this imported method is coming from.

Personally, I have used this language feature very rarely, and almost always only with constants or enums, never with methods. The trade-off, for me, is almost never worth it.

ktulinho
  • 3,870
  • 9
  • 28
  • 35
Ross
  • 9,652
  • 8
  • 35
  • 35
  • 9
    Agreed. I've used static imports veeery occasionally where they've actually made the code significantly easier to follow. – Neil Coffey Jan 07 '09 at 17:36
  • 5
    I like to use them with Collectors and streams. I feel `aStream.collect(toSet())` is more readable than `aStream.collect(Collectors.toSet())`. Would this be considered an appropriate use? – Snap Nov 03 '20 at 17:48
71

Another reasonable use for static imports is with JUnit 4. In earlier versions of JUnit methods like assertEquals and fail were inherited since the test class extended junit.framework.TestCase.

// old way
import junit.framework.TestCase;

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

In JUnit 4, test classes no longer need to extend TestCase and can instead use annotations. You can then statically import the assert methods from 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 using it this way.

Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
  • 5
    I'd agree. Simplifying test cases is one place where the intent is unlikely to be misunderstood. – Bill Michell Jan 09 '09 at 11:10
  • 7
    We've had this on our project and actually had issues with people using assert() and incorrectly thinking that it comes from their static import of the Assert package. Once we found this problem, a quick scan of our code-base found around 30 instances of this in our tests meaning that 30 assertions were NOT being run when the test framework was executed because the DEBUG flag isn't set when we run tests. – Chris Williams Dec 03 '13 at 18:49
34

Effective Java, Second Edition, at the end of Item 19 notes that you can use static imports if you find yourself heavily using constants from a utility class. I think this principle would apply to static imports of both constants and methods.

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

This has advantages and disadvantages. It makes the code a bit more readable at the expense of losing some immediate information about where the method is defined. However, a good IDE will let you go to the definition, so this isn't much of an issue.

You should still use this sparingly, and only if you find yourself using things from the imported file many, many times.

Edit: Updated to be more specific to methods, as that's what this question is referring to. The principle applies regardless of what's being imported (constants or methods).

Lii
  • 11,553
  • 8
  • 64
  • 88
Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
  • 1
    My question is about static-importing *methods*, not fields. – Miserable Variable Jan 08 '09 at 06:08
  • 10
    Perhaps `UtilityClassWithFrequentlyUsedMethods` needs to be shortened. – Steve Kuo Sep 06 '12 at 19:59
  • 5
    @SteveKuo certainly less than [InternalFrameTitlePaneMaximizeButtonWindowNotFocusedState](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/com/sun/java/swing/plaf/nimbus/InternalFrameTitlePaneMaximizeButtonWindowNotFocusedState.java#31) :P – Anirban Nag 'tintinmj' Apr 03 '14 at 18:50
  • @Rob-Hruska Couldn't I just wrap a static import method or field in a new method or field if I'm planning on using them frequently? Would that allow me to not statically import? such as: `double myPI = Math.PI;` and then I can I just keep referring to `myPI` instead of `Math.PI`. – Honinbo Shusaku Jul 08 '14 at 13:17
  • @Abdul - Yeah, you could do that. – Rob Hruska Jul 08 '14 at 13:33
25

I think static import is really useful to remove redundant class names when using utils classes like Arrays and Assertions.

Not sure why but Ross skipped out the last sentence that mentions this in the documentation he is referencing.

Used appropriately, static import can make your program more readable, by removing the boilerplate of repetition of class names.

Basically copied from this blog: https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

So for example:

Assertions in tests

This is the most obvious case which I think we all agree on

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

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

Utils classes and enums

The class name can be removed in many cases when using utils classes making the code easier to read

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

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

java.time package has a few cases where it should be used

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

Example of when NOT to use

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

// I have no idea what this is 
of("hello world");
softarn
  • 5,327
  • 3
  • 40
  • 54
17

I agree that they can be problematic from a readability perspective and should be used sparingly. But when using a common static method they can actually increase readability. For example, in a JUnit test class, methods like assertEquals are obvious where they come from. Similarly for methods from java.lang.Math.

Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
Joel
  • 1,426
  • 3
  • 16
  • 16
  • 5
    And what's so bad about seeing Math.round(d) versus round(d)? – Steve Kuo Jan 07 '09 at 17:40
  • 8
    @SteveKuo - for the same reason that mathematicians use one-letter variable names when manipulating formulas: there are times when longer names interferes with readability of the overall statement. Consider a formula involving multiple trigonometric functions. An easily grasped math formula: `sin x cos y + cos x sin y`. In Java becomes: `Math.sin(x) * Math.cos(y) + Math.cos(x) * Math.sin(y)`. Horrible to read. – ToolmakerSteve Sep 06 '14 at 18:19
  • @ToolmakerSteve, that's why I missed `using` directive in C++ so much: they can be _local_. – Franklin Yu May 01 '16 at 05:07
12

I use it for Color a lot.

static import java.awt.Color.*;

It is very unlikely that the colors will be confused with something else.

jjnguy
  • 136,852
  • 53
  • 295
  • 323
5

I recommend the use of static import when using OpenGL with Java, which is a use-case falling into the "heavy use of constants from a utility class" category

Consider that

import static android.opengl.GLES20.*;

allows you to port original C code and write something readable such as :

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

instead of that common widespread ugliness :

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);
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Flint
  • 1,651
  • 1
  • 19
  • 29
3

I use 'import static java.lang.Math.*' when porting math heavy code from C/C++ to java. The math methods map 1 to 1 and makes diffing the ported code easier without the class name qualification.

Fracdroid
  • 1,135
  • 10
  • 15
2

Static imports are the only “new” feature of Java that I have never used and don’t intend to ever use, due to the problems you just mentioned.

Bombe
  • 81,643
  • 20
  • 123
  • 127
2

Talking about unit tests: most people use static imports for the various static methods that mocking frameworks provide, such as when() or verify().

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

And of course, when using the one and only assert you should be using assertThat() it comes in handy to statically import the required hamcrest matchers, as in:

import static org.hamcrest.Matchers.*;
Yash
  • 11,486
  • 4
  • 19
  • 35
GhostCat
  • 137,827
  • 25
  • 176
  • 248
2

I found this to be very convenient when using Utility classes.

For example , instead of using : if(CollectionUtils.isNotEmpty(col))

I can instead :

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

Which IMO increases code readability when I use this utility multiple times in my code.

Yeikel
  • 854
  • 10
  • 18
1

I think static imports are neat for NLS in the gettext-style.

import static mypackage.TranslatorUtil._;

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

This both marks the string as a string that has to be extracted and provides an easy and clean way to replace the string with its translation.

Matthias Wuttke
  • 1,982
  • 2
  • 21
  • 38
1

They're useful to reduce verbiage, particularly in cases where there are a lot of imported methods being called, and the distinction between local and imported methods is clear.

One example: code that involves multiple references to java.lang.Math

Another: An XML builder class where prepending the classname to every reference would hide the structure being built

kdgregory
  • 38,754
  • 10
  • 77
  • 102
0

IMO static import is quite a nice feature. It is absolutely true that heavy reliance on static import makes the code unreadable and difficult to understand which class a static method or attribute belongs to. However, in my experience it becomes a usable feature especially when designing Util classes which provide some static methods and attributes. The ambiguity arising whenever providing static import can be circumvented by establishing code standards. In my experience within a company this approach is acceptable and makes the code cleaner and easy to understand. Preferably I insert the _ character in front static methods and static attributes (somehow adopted from C). Apparently this approach violates the naming standards of Java but it provides clarity to code. For example, if we have a AngleUtils class:

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

    }
}

In this case the static import provides clarity and code structure looks more elegant to me:

import static AngleUtils.*;

public class TestClass{

    public void testAngles(){

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

Right away someone can tell the which method or attribute comes from a static import and it hides the information of the class which it belongs to. I dont suggest using static import for classes that are integral part of a module and provide static and non-static methods as in these case it is important to know which class provides certain static functionality.

eldjon
  • 2,800
  • 2
  • 20
  • 23
  • Thanks for the suggestion re naming. BTW, an underscore in front is traditionally used in some environments to name private methods/fields. I'm considering a modified convention, such as `H_` for imports from a `Helper` utility class I have, or `C_` for `Common`, or `U_` for `Utility`. Alternatively, I've considered using one or two character class names for these widely used classes, but was concerned those might sometimes conflict with local names - have some legacy code with uppercase method names. – ToolmakerSteve Jun 24 '15 at 20:41
-1

You need to use them when:

  • you wish to use a switch statement with enum values
  • you wish to make your code difficult to understand
Meneer Venus
  • 1,039
  • 2
  • 12
  • 28
davetron5000
  • 24,123
  • 11
  • 70
  • 98
  • 9
    This is not true. (1) You can use enum constants perfectly well without a static import of them. (2) Static imports of, say, JUnit Assert class methods are clear as a bell. "assertTrue(...)" is just as readable as "Assert.assertTrue(...)", perhaps moreso. – Alan Krueger Jan 07 '09 at 19:00
  • 6
    if you have 5 static imports in a 500 line class, it is very hard to tell where methods come from. – davetron5000 Jan 13 '09 at 23:10
  • 6
    +1 for when you wish to make your code difficult to understand :) – Miserable Variable Aug 23 '10 at 09:40
  • 1
    Well yea ... but there are other **more effective** ways to make your code difficult to understand :-) – Stephen C May 13 '22 at 01:02
-6

I use them when ever I can. I have IntelliJ setup to remind me if I forget. I think it looks much cleaner than a fully qualified package name.

Javamann
  • 2,882
  • 2
  • 25
  • 22
  • 14
    You're thinking of regular imports. Static imports let you refer to members of a class without qualifying them with a classname, e.g. static import java.lang.system.out; out.println("foo"); // instead of System.out.println("foo"); – sk. Jan 07 '09 at 17:08
  • Now this is a very good explanation of static imports... too bad I can't +1 a comment – Eldelshell Jan 07 '09 at 17:23