What Is a Good Use Case for Static Import of Methods

What is a good use case for static import of methods?

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.

Are there any advantages of using static import over import?

The only difference between a normal import and an import static is that the latter is for moving static members of some other class or interface — especially constants — into scope. It's up to you whether you use it; I like it because it keeps the body of the class shorter, but YMMV.

There are no performance benefits or penalties to using them (except possibly when compiling, as if you care about that) as they compile into identical bytecode.

Is import static a good practice?

Depends on the context, not exist an explicit rule to use in all the cases. But the most common use is when you do a test and need to import classes like Assert.* or Mockito.*, in order to no-repeat Assertion.assertEquals a lot of times a good idea is to do something like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ErrorsControllerImplTest {

@Test
void should_return_all_the_errors_types() {
ErrorsController controller = new ErrorsControllerImpl();

assertAll(
() -> assertEquals(58, controller.getAllErrors().size()),
() -> assertEquals("BadRequestStatus {code=4000509, message='Site must have a value'}",
controller.getAllErrors().get(0)));
}
}

As another user said, the idea is that the code will be readable and remove duplicates parts.

Should I use static import?

As the docs say, use it sparingly. Look there for the justifications.

When to use static methods

One rule-of-thumb: ask yourself "Does it make sense to call this method, even if no object has been constructed yet?" If so, it should definitely be static.

So in a class Car you might have a method:

double convertMpgToKpl(double mpg)

...which would be static, because one might want to know what 35mpg converts to, even if nobody has ever built a Car. But this method (which sets the efficiency of one particular Car):

void setMileage(double mpg)

...can't be static since it's inconceivable to call the method before any Car has been constructed.

(By the way, the converse isn't always true: you might sometimes have a method which involves two Car objects, and still want it to be static. E.g.:

Car theMoreEfficientOf(Car c1, Car c2)

Although this could be converted to a non-static version, some would argue that since there isn't a "privileged" choice of which Car is more important, you shouldn't force a caller to choose one Car as the object you'll invoke the method on. This situation accounts for a fairly small fraction of all static methods, though.

Java static imports

The explanation is simple although it doesn't change the fact that the behavior is highly unintuitive:

When resolving the method to be invoked the first thing the compiler does is find the smallest enclosing scope that has a method of the right name. Only then come other things like overload resolution and co in game.

Now what is happening here is that the smallest enclosing scope that contains a toString() method is class A which inherits it from Object. Hence we stop there and don't search farther. Sadly next the compiler tries to find the best fit of the methods in the given scope and notices that it can't call any of those and gives an error.

Which means never statically import methods with a name that is identical to a method in Object, because methods that are naturally in scope take precedence over static imports (the JLS describes method shadowing in detail, but for this problem I think it's much simpler to just remember that).

Edit: @alf kindly submitted the right part of the JLS that describes the method invocation for those who want the whole picture. It's rather complex, but then the problem isn't simple either so that's to be expected.

Why are static imports of static methods with same names legal?

The ambiguity of the static imports of methods could be resolved at the point of the method invocation.

For example if you had a static import for two methods that look like this:

void frobnicate(int i);
// and
void frobnicate(boolean b);

Then you could import and use both, because the compiler could tell which one to use, based on the arguments you pass in (frobnicate(1) calls the first one, frobnicate(true) calls the second one).

With classes, that's not possible: Foobar a; alone is not sufficient to tell you which of the two Foobar classes you want.

Also note that a single static import can import multiple names. According to the relevant section of the JLS (emphasis mine):

A single-static-import declaration imports all accessible static members with a given simple name from a type.

For example if the two frobnicate methods above where located in the same class, a single static import could import them both.



Related Topics



Leave a reply



Submit