stolsvik
stolsvik

Reputation: 5341

declare function.Consumer<T> that can consume everything?

In Java, are there any way to declare a Consumer that can be fed to any method requiring a specific Consumer?

I'll try to illustrate:

A createA(String someVar, Consumer<ThingAConfig> configLambda);
B createB(String someVar, Consumer<ThingBConfig> configLambda);

Consumer<?> NO_CONFIG = c -> {}

createA("", NO_CONFIG);  // does not work, "argument mismatch"
createB("", NO_CONFIG);  // does not work, "argument mismatch"

One thing that does work, is to make a raw Consumer:

Consumer RAW_NO_CONFIG = c -> {}

But then you get "unchecked conversion" upon usage.

createA("", RAW_NO_CONFIG);  // "works" with "unchecked conversion"
createB("", RAW_NO_CONFIG);  // "works" with "unchecked conversion"

It seems too strict to not be able to make something like that, as there are plenty of reasons why I would want a consumer that can eat anything.

Upvotes: 0

Views: 194

Answers (3)

Alex - GlassEditor.com
Alex - GlassEditor.com

Reputation: 15537

Another work around is to call a method like this to get a Consumer of the needed type:

public static <T> Consumer<T> emptyConsumer(){
    return t -> {};
}
...
createA("", emptyConsumer());

//Of course you could also just do this in this case:
createA("", c -> {});

Or if you can wait for Java 10 there is a JEP open which will allow the creators of an interface or class to specify the wildcard for you, so your methods will be equivalent to the one in JB Nizet's answer.

Upvotes: 2

11thdimension
11thdimension

Reputation: 10653

There are 2 ways of doing this

A createA(String someVar, Consumer<?> configLambda)

Consumer can accept any type. We can limit it to an extent in following ways

A createA(String someVar, Consumer<? extends ParentType> configLambda)
//meaning passed type should be ParentType or child of ParentType

A createA(String someVar, Consumer<? super ChildType> configLambda)
//meaning passed type should be ChildType or some parent of ChildType

The other way to do it is

<T> A createA(String someVar, Consumer<T> configLambda)

In this case too it can accept any type, most of the time Java should be able to infer the type T by the type of the variable passed, if not you'll have to manually pass the type information.

//without explicit type
myClassObj.createA("", new Consumer<SomeType>);

//with explicit type
myClassObj.<SomeType>createA("", new Consumer<SomeType>);

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 692023

The problem is with the signature of createA() and createB(). they should be

A createA(String someVar, Consumer<? super ThingAConfig> configLambda);

That way, you'll be able to pass a Consumer<ThingAConfig>, or a Consumer<Object> (that can eat anything), or a consumer of any superclass or super-interface of ThingAConfig.

If you stick with Consumer<ThingAConfig> as argument type, then the only thing you can pass is a Consumer<ThingAConfig>.

Upvotes: 4

Related Questions