Why do suppliers only support no-arg constructors?
If the default constructor is present, I can do this:
create(Foo::new)
But if th
When looking for a solution to the parametrized Supplier
problem, I found the above answers helpful and applied the suggestions:
private static <T, R> Supplier<String> failedMessageSupplier(Function<String,String> fn, String msgPrefix, String ... customMessages) {
final String msgString = new StringBuilder(msgPrefix).append(" - ").append(String.join("\n", customMessages)).toString();
return () -> fn.apply(msgString);
}
It is invoked like this:
failedMessageSupplier(String::new, msgPrefix, customMsg);
Not quite satisfied yet with the abundant static function parameter, I dug further and with Function.identity(), I came to the following result:
private final static Supplier<String> failedMessageSupplier(final String msgPrefix, final String ... customMessages) {
final String msgString = new StringBuilder(msgPrefix).append(" - ").append(String.join("\n", customMessages)).toString();
return () -> (String)Function.identity().apply(msgString);
};
Invocation now without the static function parameter:
failedMessageSupplier(msgPrefix, customMsg)
Since Function.identity()
returns a function of the type Object
, and so does the subsequent call of apply(msgString)
, a cast to String
is required - or whatever the type, apply() is being fed with.
This method allows for e. g. using multiple parameters, dynamic string processing, string constants prefixes, suffixes and so on.
Using identity should theoretically also have a slight edge over String::new, which will always create a new string.
As Jacob Zimmerman already pointed out, the simpler parametrized form
Supplier<Foo> makeFooFromString(String str1, String str2) {
return () -> new Foo(str1, str2);
}
is always possible. Whether or not this makes sense in a context, depends.
As also described above, static Method reference calls require the corresponding method's number and type of return / parameters to match the ones expected by the function-consuming (stream) method.
The Supplier<T>
interface represents a function with a signature of () -> T
, meaning it takes no parameters and returns something of type T
. Method references that you provide as arguments must follow that signature in order to be passed in.
If you want to create a Supplier<Foo>
that works with the constructor, you can use the general bind method that @Tagir Valeev suggests, or you make a more specialized one.
If you want a Supplier<Foo>
that always uses that "hello"
String, you could define it one of two different ways: as a method or a Supplier<Foo>
variable.
method:
static Foo makeFoo() { return new Foo("hello"); }
variable:
static Supplier<Foo> makeFoo = () -> new Foo("hello");
You can pass in the method with a method reference(create(WhateverClassItIsOn::makeFoo);
), and the variable can be passed in simply using the name create(WhateverClassItIsOn.makeFoo);
.
The method is a little bit more preferable because it is easier to use outside of the context of being passed as a method reference, and it's also able to be used in the instance that someone requires their own specialized functional interface that is also () -> T
or is () -> Foo
specifically.
If you want to use a Supplier
that can take any String as an argument, you should use something like the bind method @Tagir mentioned, bypassing the need to supply the Function
:
Supplier<Foo> makeFooFromString(String str) { return () -> new Foo(str); }
You can pass this as an argument like this: create(makeFooFromString("hello"));
Although, maybe you should change all the "make..." calls to "supply..." calls, just to make it a little clearer.