3

I have a co worker who need a method to be available to two classes.

He decided to create a new interface to be implemented by those classes.

The interface has one method default doThis(String parameter)

It does not have any other interface methods, there is no indication that other methods would be added to this interface.

I feel this is an incorrect usage of the interface and it should be done in a different way. I.e perhaps a class which has the method allowing other classes to consume this by using the object.

Does anyone with experience on this have any opinions to share?

I can update with more clarification based on your comments.

Update:

Here is the code and the question remains: is this a valid use of the default method or should this common logic have been done in another way like a Utilities class which does the saving to preferences ?

Interface:

public interface LogInCookie {

    default void mapCookiesToPreferences(String cookie) {
        if (cookie.contains(MiscConstants.HEADER_KEY_REFRESH)) {
            String refreshToken = cookie.replace(MiscConstants.HEADER_KEY_REFRESH, StringUtils.EMPTY);
            SharedPrefUtils.addPreference(SharedPrefConstants.REFRESH_TOKEN, refreshToken);
        } 
    }
}
public class HDAccountActivity extends AbstractActivity implements LogInCookie {

    private void mapCookies(List<String> mValue) {
       LogInCookie.super.mapCookiesToPreferences(mValue); //ekh!
    }

}
public class BaseSplashPage extends AppCompatActivity implements DialogClickedCallBack, LogInCookie {

//method which uses this
private void mapCookiesToPreferences(List<String> headers) {
        int firstItemInHeader = 0;
        for (String header : headers) {
            String  mValue =  header.substring(firstItemInHeader,header.indexOf(MiscConstants.SEMICOLON));
            LogInCookie.super.mapCookiesToPreferences(mValue);  //ekh!
        }
    }

}
11
  • 1
    Java allows doing this. But I think that, the best and clear way to implement these common methods are 1) create a new abstract class end extend it 2) create a final class with static methods. I personally not recommend using interface for this purpose. Commented Mar 11, 2020 at 13:02
  • 1
    @ahsan.dev In that case it is a weird way to use an interface. Commented Mar 11, 2020 at 14:19
  • 1
    @ahsan.dev Tough to get a definitive answer to a question with little detail about the entities and purposes involved. Commented Mar 11, 2020 at 14:45
  • 2
    That method looks like something that could easily be in a separate class as a helper function. Commented Mar 11, 2020 at 16:04
  • 2
    @ahsan.dev I think Holger's answer is reasonable. I would say that the interface is completely unnecessary, and therefore it is confusing. Commented Mar 11, 2020 at 16:24

4 Answers 4

5

A default method in an interface, which doesn’t define other methods, can’t do much useful things with the instance of the implementing class. It can only use methods inherited from java.lang.Object, which are unlikely to carry semantics associated with the interface.

If the code doesn’t use instance methods on this at all, in other words, is entirely independent from the this instance, you should make it static, change the containing class to a non-instantiable class type, i.e.

final class SomeUtilClass {
    static void doThis(String parameter) {
    // ...
    }

    private SomeUtilClass() {} //no instances
}

and use import static packageof.SomeUtilClass.doThis; in the classes using this method.

That way, all these classes can invoke the method like doThis(…) without a qualifying type name, without needing a misleading type hierarchy.

When the method actually uses the this instance, which, as said, can only be in terms of methods inherited from java.lang.Object, the type inheritance might be justified. Since this is rather unlikely, you might still consider the type hierarchy to be misleading and rewrite the code to

final class SomeUtilClass {
    static void doThis(Object firstParameter, String parameter) {
    // ...
    }

    private SomeUtilClass() {} //no instances
}

using firstParameter instead of this, which can be invoke like doThis(this, …).

Sign up to request clarification or add additional context in comments.

4 Comments

Would we not need to use PowerMock to test the static method? I thought static methods are bad for this reason and ought to be avoided where possible for testing sakes?
When you want to test a method, you should call it with prepared input and verify that it produces the expected output. That’s how unit testing works. Most of the time, a mocking tool is used, it is used the wrong way. You rarely need mocking tools for testing. And there’s no fundamental difference between a default method and a static method in this regard. The way, your coworker uses it, you can’t intercept the invocation without mocking in either case (but as said, you normally rarely need this for unit testing).
@Holger there is a hidden dependency. You can probably see it with: SharedPrefUtils. Does this help clarify this?
No, I don’t get it. Say, I have void foo() { var x = new ArrayList<>(); } then, I have a “hidden dependency” to ArrayList, not recognizable from foo’s signature. Now, I have void foo() { var x = Collections.singletonList(42); } instead. In that case I have a “hidden dependency” to the Collections class, whose static method I invoke. So how is invoking a static method different from any other “X uses Y internally” scenario?
1

Ideally you would put that method doThis() in an abstract class that both classes extend. However if you need to achieve multiple inheritance then using an interface here is fine.

A class with a static method doThis() that you can call staticly would also work.

It all depends on how you have your project organized imo.

2 Comments

"Ideally you would put that method doThis() in an abstract class that both classes extend." ... I can't agree that this solution would be "ideal". There are several reasons why it is often a better strategy to define a type in Java using an interface.
@joe Caruso:I With the static suggestion, I figure we would need PowerMock to be able to test the method. I have been under the impression that using static methods are bad for that reason. Do you have any comment on this?
1

In java 8 , default keyword in interface was introduced for those cases where if any set of apis had long inheritance hierarchy and we wanted to introduce a method that should be available in all of the lower lying classes.

So for ex. in Java 8 stream() method was introduced in the Collection interface as a default method and it ended up being available in all of the underlying classes.

As far as your case in considered , if I go by your words then if yours is a new development then you should be using interface -> abstract class -> actual implementing class.

Only if yours was an older development setup and you already had classes implementing from an interface , that could have been an ideal scenario for using default method in your interface.

3 Comments

"default keyword in interface was introduced for those cases where if any set of apis had long inheritance hierarchy" ... not really. Default methods were added in Java 8 in order to support the new language extensions (lambdas and streams, especially). Without this facility, several of the existing interfaces would have become broken.
@rootExplorr I personally agree with this answer, however I am not sure its the definitive truth here.
@scottb exactly. In order to make available stream() method to a long list of collection hierarchy default methods were introduced. That is what i meant.
0

A default method in an interface
*)can have a default implementation
*)which can overridden by the implementing class

yes its a correct usage since JAVA8.
we can have default method in an interface as well as a abstract method

1 Comment

While you 'can' do it, is it the correct usage? We can also use Charsequence instead of Strings when we are dealing with Strings only. However using CharSequence isn't the correct usage if its not needed right? example: ``` private void doThat(CharSequence sequence) { sequence = "a whole bunch of characters"; } ``` Unless there is a reason to use it, I am not sure why we would use it. In my case, I am not sure there is a reason to use the default keyword within the interface. It seems like a new approach to an existing problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.