Can explicit type parameters redundant?
Asked Answered
E

2

6

I have a class with a type parameter.

class MyObject<IdType> {

    @Setter
    @Getter
    private IdType id;
}

And I thought I can add some method for conveniency so I did.

<T extends MyObject<? super IdType>> void copyIdTo(T object) {
    object.setId(getId());
}

< T extends MyObject<? extends IdType>> void copyIdFrom(T object) {
    object.copyIdTo(this);
}

And I just realized that I can do this.

void copyIdTo(MyObject<? super IdType> object) {
    object.setId(getId());
}

void copyIdFrom(MyObject<? extends IdType> object) {
    object.copyIdTo(this);
}

Are those two sets of methods are equivalent? Which way (or style) is prefer?

Expedition answered 26/6, 2019 at 7:14 Comment(3)
As those methods return void, prefer the latter. If they returned the argument then using the former could be useful since you could return T (an example would be Objects.requireNonNull).Oxyacid
As long as the method type parameter is only used once I prefer the second styleGhislainegholston
You only need to introduce a T if you want to use it in more than one place (return type or multiple method arguments or generic argument with multiple types itself, such as Pair<T,T>)Triage
O
5

In your case, the two approaches are effectively equivalent. They both restrict the argument's type to MyObject<...> or a subtype.

Since your example methods return void there's no real benefit from making the method generic. The only important thing for your method is that the argument is a MyObject<...>—beyond that the real type is meaningless. Adding the ability to make the argument's type more specific adds nothing for the method's implementation and does nothing for the caller. In other words, it's irrelevant "fluff".

So for your examples, I would say prefer the non-generic option. It's cleaner and more straightforward.


However, if your methods returned the given argument back to the caller then making the method generic could prove useful; it would allow you to declare the return type as T. This opens up possibilities to the caller such as method chaining or invoking the method "inside" another method call, all based on the specific type passed as an argument. An example of this in the core library would be Objects.requireNonNull(T).

Another good case for making the method generic is mentioned by @Thilo in the comments:

Another case would be if your method takes multiple arguments. Then you can introduce a T to make sure those two arguments have the same type (instead of two distinct types that happen to [fulfill] the constraints individually).

Oxyacid answered 26/6, 2019 at 7:40 Comment(1)
Another case would be if your method takes multiple arguments. Then you can introduce a T to make sure those two arguments have the same type (instead of two distinct types that happen to fulfil the constraints individually).Triage
S
2

Yes they are equivalent. Both sets of methods declare the same thing - that the method parameter must be of type MyObject<> or a compatible subtype (subclass).

The only reason to declare T in this way is if you need to refer to T elsewhere, such as the return type of the method, or if you have multiple parameters of the same type, or inside the method body.

I would always prefer the shorter, simpler, clearer version with less angle brackets to hurt the eyeballs :)

Saudra answered 26/6, 2019 at 8:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.