13

I've just recently noticed there is an option to have static methods in interfaces. Same as with static fields of interface, there is an interesting behavior: These are not inherited.

I'm unsure it's any useful in the actual interfaces that are to be implemented. However, it enables the programmer to create interfaces that are just envelopes for static stuff, like e.g. utility classes are.

A simple example is just an envelope for global constants. Compared to a class, you can easily notice the missing boilerplate of public static final as those are assumed (making it less verbose).

public interface Constants {
    String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
    int DEFAULT_TIMEOUT_MS = 30;
}

You could also make something more complex, like this pseudo-enum of config keys.

public interface ConfigKeys {
    static createValues(ConfigKey<?>... values) {
        return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
    }

    static ConfigKey<T> key(Class<T> clazz) {
        return new ConfigKey<>(clazz);
    }

    class ConfigKey<T> {
        private final Class<T> type;
        private ConfigKey(Class<T> type) {
            this.type = type;
        }
        private Class<T> getType() {
            return type;
        }
    }
}

import static ConfigKeys.*;
public interface MyAppConfigKeys {
    ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
    ConfigKey<String> COMPANY_NAME = key(String.class);

    Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);

    static values() {
        return VALUES;
    }
}

You could also create some utility "class" this way. However, in utilities, it is often useful to use private or protected helper methods, which is not quite possible in classes.

I consider it a nice new feature, and especially the fact the static members aren't inherited is an interesting concept that was introduced to interfaces only.

I wonder if you can consider it a good practice. While code style and best practices aren't axiomatic and there is room for opinion, I think there are usually valid reasons backing the opinion.

I'm more interested in the reasons (not) to use patterns like these two.


Note that I don't intend to implement those interfaces. They are merely an envelope for their static content. I only intend to use the constants or methods and possibly use static import.

Robert Harvey
  • 200,592
Vlasec
  • 281

5 Answers5

1

A simple example is just an envelope for global constants.

Putting constants on interfaces is called the Constant Interface Antipattern since constants are often merely an implementation detail. Further drawbacks are summarized in the Wikipedia article on the Constant interface.

You could also create some utility "class" this way.

Indeed the Java doc states that static methods can make it easier to organize helper methods, for example when calling helper methods from default methods.

1

As stated in the question, the interface is not meant to be implemented (or instantiated). So we could compare it with a class that has a private constructor:

  • The class can't be extended with no super() to call, but interface can be "implemented"
  • The class can't be instantiated without reflections, while the interface can be easily instantiated as an anonymous class as simple as this: new MyInterface() {};

This comparison is in favor of class as it allows more control. That said, class is not intended to be a holder of static stuff either, you'd expect it to have instances. Well, there is no perfect option.

There is also a weird thing about inheritance from the "static interface":

  • An "implementing" class inherits fields, but doesn't inherit static methods
  • An extending interface inherits no static members at all
  • (While a class extending a class inherits every non-private member ... and since it can't be extended by an interface, there is less room for confusion)

These might be reasons to consider it a bad pattern and keep using static classes for these cases. However, for someone addicted to syntactic sugar it may still be tempting even with the downsides.

Vlasec
  • 281
0

As @MarkusPscheidt this idea is essentially an extension of the Constant Interface antipattern. This approach was initially used widely to allow a single set of constants to be inherited by many disparate classes. The reason this ended being considered an antipattern was because of the issues that were encountered using this approach in real projects. I see no reason to think that these problems would only relate to constants.

Probably more importantly, there's really no need to do this. Use static imports instead and be explicit about what you are importing and from where.

JimmyJames supports Canada
  • 30,578
  • 3
  • 59
  • 108
0

I would say, if you're interested in how to use the new feature properly, take a look at the code in the JDK. Default methods on interfaces are very widely used and easy to find, but static methods on interfaces seem to be very uncommon. Some examples include java.time.chrono.Chronology, java.util.Comparator, java.util.Map, and quite a few interfaces in java.util.function and java.util.stream.

Most of the examples I looked at involve uses of those APIs that are likely to be very common: conversion between different types in the time API, for example, for comparisons that are likely to be done frequently between objects passed to functions or objects contained in collections. My takeaway: if there's a part of your API that needs to be flexible, but you can cover say 80% of use cases with a handful of defaults, consider using static methods on your interfaces. Given how infrequently this feature seems to be used in the JDK, I would be very conservative when making use of it in my own code.

Your examples don't look anything like what I see in the JDK. For those specific cases, you should almost certainly be creating an enum that implements the desired interface. An interface describes a set of behaviors and really has no business maintaining a collection of its implementations.

ngreen
  • 799
-1

I wonder if there are reasons not to use it.

How about, um, compatibility with older JVMs?

Do you consider this a good idea in general?

No. It is a backwards-incompatible change that adds zilch to the expressivity of the language. Two thumbs down.

Are there some model situations where you strongly recommend classes?

I strongly recommend using classes to contain implementation details. An interface is really just meant to say "this Object supports operations XYZ" and that has nothing to do with any static methods you may think of putting in the interface declaration. This feature is like a recliner with a built-in mini-fridge. Sure it has some niche uses but it doesn't pull enough weight to deserve being mainstream.

UPDATE: Please no more downvotes. Clearly some people think static methods in interfaces are the bee's knees, and I'm hereby capitulating. I'd just as soon delete this answer but the comments attached to it are an interesting discussion.