Java Functional Interface with one argument can apply to no argument method? - java

References
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/package-summary.html
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/String.html#isEmpty()
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/ToIntFunction.html
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Integer.html#intValue()
This is Predicate Functional Interface's abstract method. It gets one argument T t and return boolean.
boolean test​(T t)
Evaluates this predicate on the given argument.
But, in this example, String::isEmpty does not get any argument but it is instance method of String.
Predicate<String> p = String::isEmpty;
I can infer that in Java, this type of method can apply to Functional Interface with one argument.
And, is there any examples of one argument Functional Interface with the function has one argument not like upper example?

There are three forms that a Predicate can take. Here they are for isEmpty on a String:
1- A formal functional interface:
Predicate<String> somePredicate = new Predicate<String>() {
#Override
public boolean test(String s) {
return s.isEmpty();
}
};
2- A lambda:
(String s) -> s.isEmpty()
3- A method reference
String::isEmpty
These have identical function and can each be passed when a Predicate<String> is required.
The third doesn't apply if the underlying function is not a method on an object.

You can do Function<T, R> where R is the return type and T is the argument type.
So R result = fnc.apply(k) where k is of type T.
Function<Integer, List<Integer>> fnc = n-> new ArrayList<>(List.of(n));
List<Integer> list = fnc.apply(23);
System.out.println(list);
prints
[23]
But you can also do this, just like in your example.
Function<Integer, List<Integer>> fnc2 = fnc::apply;
fnc2.apply(44); // returns a list which contains 44
EXTRA DETAILS
Consider the following class. One static and one instance method.
class TestClass {
public int prod(int a) {
return a * 33;
}
public static int mult(int a) {
return a * 44;
}
}
To create a Lambda for the static, do the following:
// use unaryOperator since return type are argument are the same
UnaryOperator<Integer> fnc = TestClass::mult;
int result = fnc.apply(10); // returns 440
Now do an instance version.
UnaryOperator<Integer> inst = tc::prod;
inst.apply(10);
result = inst.apply(10); // returns 330
Now a special case using a static type reference.
to an instance method.
// This requires 2 arguments. The instance
// and the argument to the method.a
BiFunction<TestClass, Integer, Integer> stat = TestClass::prod
result = stat.apply(tc, 12); // result is 396

Related

Java 8 stream max() function argument type Comparator vs Comparable

I wrote some simple code like below. This class works fine without any errors.
public class Test {
public static void main(String[] args) {
List<Integer> intList = IntStream.of(1,2,3,4,5,6,7,8,9,10).boxed().collect(Collectors.toList());
int value = intList.stream().max(Integer::compareTo).get();
//int value = intList.stream().max(<Comparator<? super T> comparator type should pass here>).get();
System.out.println("value :"+value);
}
}
As the code comment shows the max() method should pass an argument of type Comparator<? super Integer>.
But Integer::compareTo implements Comparable interface - not Comparator.
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
How can this work? The max() method says it needs a Comparator argument, but it works with Comparable argument.
I know I have misunderstood something, but I do now know what. Can someone please explain?
int value = intList.stream().max(Integer::compareTo).get();
The above snippet of code is logically equivalent to the following:
int value = intList.stream().max((a, b) -> a.compareTo(b)).get();
Which is also logically equivalent to the following:
int value = intList.stream().max(new Comparator<Integer>() {
#Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
}).get();
Comparator is a functional interface and can be used as a lambda or method reference, which is why your code compiles and executes successfully.
I recommend reading Oracle's tutorial on Method References (they use an example where two objects are compared) as well as the Java Language Specification on §15.13. Method Reference Expressions to understand why this works.
I can relate to your confusion.
We've got a Comparator's method which declares two parameters
int compare(T o1, T o2);
and we've got an Integer's method which takes one parameter
int compareTo(Integer anotherInteger)
How on earth does Integer::compareTo get resolved to a Comparator instance?
When a method reference points to an instance method, the parser can look for methods with arity n-1 (n is the expected number of parameters).
Here's an excerpt from the JLS on how applicable methods are identified. I will drop the first part about parsing the expression preceding the :: token.
Second, given a targeted function type with n parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form ReferenceType :: [TypeArguments] Identifier, then the potentially applicable methods are:
the member methods of the type to search that would be potentially applicable (§15.12.2.1) for a method invocation which names Identifier, has arity n, has type arguments TypeArguments, and appears in the same class as the method reference expression; plus
the member methods of the type to search that would be potentially applicable for a method invocation which names Identifier, has arity n-1, has type arguments TypeArguments, and appears in the same class as the method reference expression.
Two different arities, n and n-1, are considered, to account for the possibility that this form refers to either a static method or an instance method.
...
A method reference expression of the form ReferenceType :: [TypeArguments] Identifier can be interpreted in different ways. If Identifier refers to an instance method, then the implicit lambda expression has an extra parameter compared to if Identifier refers to a static method.
https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.13.1
If we were to write an implicit lambda expression from that method reference, the first (implicit) parameter would be an instance to call the method on, the second (explicit) parameter would be an argument to pass in the method.
(implicitParam, anotherInteger) -> implicitParam.compareTo(anotherInteger)
Note that a method reference differs from a lambda expression, even though the former can be easily transformed into the latter. A lambda expression needs to be desugared into a new method, while a method reference usually requires only loading a corresponding constant method handle.
Integer::compareTo implements Comparable interface - not Comparator.
Integer::compareTo as an expression doesn't implement any interface. However, it can refer to/represent different functional types, one of which is Comparator<Integer>.
Comparator<Integer> a = Integer::compareTo;
BiFunction<Integer, Integer, Integer> b = Integer::compareTo;
ToIntBiFunction<Integer, Integer> c = Integer::compareTo;
Integer implements Comparable by overriding compareTo.
That overriden compareTo, however, can be used in a way that satisfies and implements the Comparator interface.
In its usage here
int value = intList.stream().max(Integer::compareTo).get();
it's translated to something like
int value = intList.stream().max(new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
}).get();
A method reference (or lambda expression) must satisfy the signature of the corresponding functional interface's single abstract method and, in this case (Comparator), compareTo does.
The idea is that max expects a Comparator and its compare method expects two Integer objects. Integer::compareTo can satisfy those expectations because it also expects two Integer objects. The first is its receiver (the instance on which the method is to be called) and the second is the argument. With the new Java 8 syntax, the compiler translates one style to the other.
(compareTo also returns an int as required by Comparator#compare.)
First trick: all instance methods actually take 1 additional implicit argument, the one you refer to as this in method body. E.g.:
public final class Integer extends Number implements Comparable<Integer> {
public int compareTo(/* Integer this, */ Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
}
Integer a = 10, b = 100;
int compareResult = a.compareTo(b);
// this actually 'compiles' to Integer#compareTo(this = a, anotherInteger = b)
Second trick: Java compiler can "transform" the signature of a method reference to some functional interface, if the number and types of arguments (including this) satisfy:
interface MyInterface {
int foo(Integer bar, Integer baz);
}
Integer a = 100, b = 1000;
int result1 = ((Comparator<Integer>) Integer::compareTo).compare(a, b);
int result2 = ((BiFunction<Integer, Integer, Integer>) Integer::compareTo).apply(a, b);
int result3 = ((MyInterface) Integer::compareTo).foo(a, b);
// result1 == result2 == result3
As you can see class Integer implements none of Comparator, BiFunction or a random MyInterface, but that doesn't stop you from casting the Integer::compareTo method reference as those interfaces.

varargs as input parameter to a function in java 8

In Java 8, how is a Function is defined to fit varargs.
we have a function like this:
private String doSomethingWithArray(String... a){
//// do something
return "";
}
And for some reason I need to call it using Java 8 function (because 'andThen' can be used along with other functions.)
And thus I wanted to define it something as given below.
Function<String... , String> doWork = a-> doSomethingWithArray(a) ;
That gives me compilation error.Following works, but input is now has to be an array and can not be a single string.
Function<String[] , String> doWork = a-> doSomethingWithArray(a) ;
Here I mentioned String, but it can be an array of any Object.
Is there a way to use varargs(...)instead of array([]) as input parameter?
Or if I create a new interface similar to Function, is it possible to create something like below?
#FunctionalInterface
interface MyFunction<T... , R> {
//..
}
You cannot use the varargs syntax in this case as it's not a method parameter.
Depending on what you're using the Function type for, you may not even need it at all and you can just work with your methods as they are without having to reference them through functional interfaces.
As an alternative you can define your own functional interface like this:
#FunctionalInterface
public interface MyFunctionalInterface<T, R> {
R apply(T... args);
}
then your declaration becomes:
MyFunctionalInterface<String, String> doWork = a -> doSomethingWithArray(a);
and calling doWork can now be:
String one = doWork.apply("one");
String two = doWork.apply("one","two");
String three = doWork.apply("one","two","three");
...
...
note - the functional interface name is just a placeholder and can be improved to be consistent with the Java naming convention for functional interfaces e.g. VarArgFunction or something of that ilk.
Because arrays and varargs are override-equivalent, the following is possible:
#FunctionalInterface
interface VarArgsFunction<T, U> extends Function<T[], U> {
#Override
U apply(T... args);
}
// elsewhere
VarArgsFunction<String, String> toString =
args -> Arrays.toString(args);
String str = toString.apply("a", "b", "c");
// and we could pass it to somewhere expecting
// a Function<String[], String>
That said, this has a pitfall having to do with invoking the method generically. The following throws a ClassCastException:
static void invokeApply() {
VarArgsFunction<Double, List<Double>> fn =
Arrays::asList;
List<Double> list = invokeApply(fn, 1.0, 2.0, 3.0);
}
static <T, U> U invokeApply(VarArgsFunction<T, U> fn,
T arg0, T arg1, T arg2) {
return fn.apply(arg0, arg1, arg2); // throws an exception
}
(Example in action.)
This happens because of type erasure: invoking the apply method generically creates an array whose component type is the erasure of the type variable T. In the above example, since the erasure of the type variable T is Object, it creates and passes an Object[] array to the apply method which is expecting a Double[].
Overriding the apply method with generic varargs (and more generally writing any generic varargs method) will generate a warning and that's why. (The warning is mandated in 8.4.1 of the JLS.)
Because of that, I don't actually recommend using this. I've posted it because, well, it's interesting, it does work in simpler cases and I wanted to explain why it probably shouldn't be used.
One safe way to target a varargs method to a strongly typed Function is by using a technique called currying.
For example, if you need to target your varargs method with 3 arguments, you could do it as follows:
Function<String, Function<String, Function<String, String>>> doWork =
a1 -> a2 -> a3 -> doSomethingWithArray(a1, a2, a3);
Then, wherever you need to call the function:
String result = doWork.apply("a").apply("b").apply("c");
This technique works to target not only varargs methods, but also any method with any number of arguments of different types.
If you already have an array with the arguments, just use a Function<String[], String>:
Function<String[], String> doWork = a -> doSomethingWithArray(a);
And then:
String[] args = {"a", "b", "c"};
String result = doWork.apply(args);
So, whenever you have a fixed number of arguments, use currying. And whenever you have dynamic arguments (represented by an array), use this last approach.
Short answer
This doesn't seem possible. Function interface has only four methods, and none of those methods takes vararg arguments.
Extend Function interface?
Doesn't work either. Since arrays are somewhat strange low-level constructs in Java, they do not work well with generic types because of type erasure. In particular, it is not possible to create an array of generic type without contaminating your entire codebase with Class<X>-reflection-thingies. Therefore, it's not even feasible to extend the Function<X, Y> interface with a default method which takes varargs and redirects to apply.
Syntax for array creation, helper methods
If you statically know the type of the arguments, then the best thing you can do is to use the inline syntax for array creation:
myFunction.apply(new KnownType[]{x, y, z});
instead of the varargs, which you want:
myFunction.apply(x, y, z); // doesn't work this way
If this is too long, you could define a helper function for creation of
arrays of KnownType from varargs:
// "known type array"
static KnownType[] kta(KnownType... xs) {
return xs;
}
and then use it as follows:
myFunction.apply(kta(x, y, z, w))
which would at least be somewhat easier to type and to read.
Nested methods, real varargs
If you really (I mean, really) want to pass arguments of known type to a black-box generic Function using the vararg-syntax, then you need something like nested methods. So, for example, if you want to have this:
myHigherOrderFunction(Function<X[], Y> blah) {
X x1 = ... // whatever
X x2 = ... // more `X`s
blah(x1, x2) // call to vararg, does not work like this!
}
you could use classes to emulate nested functions:
import java.util.function.*;
class FunctionToVararg {
public static double foo(Function<int[], Double> f) {
// suppose we REALLY want to use a vararg-version
// of `f` here, for example because we have to
// use it thousand times, and inline array
// syntax would be extremely annoying.
// We can use inner nested classes.
// All we really need is one method of the
// nested class, in this case.
class Helper {
// The inner usage takes array,
// but `fVararg` takes varargs!
double fVararg(int... xs) {
return f.apply(xs);
}
double solveTheActualProblem() {
// hundreds and hundreds of lines
// of code with dozens of invokations
// of `fVararg`, otherwise it won't pay off
// ...
double blah = fVararg(40, 41, 43, 44);
return blah;
}
}
return (new Helper()).solveTheActualProblem();
}
public static void main(String[] args) {
Function<int[], Double> example = ints -> {
double d = 0.0;
for (int i: ints) d += i;
return d / ints.length;
};
System.out.println(foo(example)); // should give `42`
}
}
As you see, that's a lot of pain. Is it really worth it?
Conclusion
Overall, this seems to be an idea which would be extremely painful to implement in Java, no matter what you do. At least I don't see any simple solutions. To be honest, I also don't see where it would be really necessary (maybe it's just me vs. the BLUB-paradox).
Unfortunately, adding a method to intercede and do the translation for you was all I could come up with.
public class FunctionalTest {
public static void main( String[] args ) {
kludge( "a","b","c" );
}
private static Function<String[],PrintStream> ref = a -> System.out.printf( "", a );
public static void kludge( String... y ) {
ref.apply( y );
}
}

When is ti appropriate to use declare generic argumens for the methods instead of simply usinf super class? [duplicate]

As far as I know, using an upper bounded generic and using a superclass as a method parameter both accept the same possible arguments. Which is preferred, and what's the difference between the two, if any?
Upper bounded generic as parameter:
public <T extends Foo> void doSomething(T foo) {}
Superclass as parameter:
public void doSomething(Foo foo) {}
That's an upper bounded type parameter. Lower bounds are created using super, which you can't really do for a type parameter. You can't have a lower bounded type parameter.
And that would make a difference, if you, for example want to pass a List<T>. So, for the below two methods:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
And for the given class:
class Bar extends Foo { }
The following method invocation:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
is valid for 1st method, but not for 2nd method. 2nd method fails because a List<Foo> is not a super type of List<Bar>, although Foo is super type of Bar. However, 1st method passes, because there the type parameter T will be inferred as Bar.
Generally, you only need a type variable when it's used in more than one place in class/method/field declarations. When you declare one on a method (rather than a class), the only places to use it are on the parameters and return value of that method.
For example, you can use it on multiple parameters to ensure their types match:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
This is a trivial example, but you can see that it prevents you from giving it an element that doesn't match the list's generic type:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
You can also declare a parameter and the return type to be the same type:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
Since this method is returning one of the two T objects it's given, we can safely say that the returned object is also of type T.
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
As for the example in the question, the type variable is only being used once, so it's equivalent to using the superclass. In this case you should avoid declaring a type variable, it's just unnecessary clutter.
Also I should note that the other answer changes the example to use List<T> and List<Foo>, but as mentioned in the comments, the superclass is really List<? extends Foo>, so no type variable is needed there, either.

Generic Method That takes unique parameter and returns unique parameters Java

I have a requirement where in the function takes different parameters and returns unique objects. All these functions perform the same operation.
ie.
public returnObject1 myfunction( paramObject1 a, int a) {
returnObject1 = new returnObject1();
returnObject1.a = paramObject1.a;
return returnObject1;
}
public returnOject2 myfunction( paramObject2 a, int a){
returnObject2 = new returnObject2();
returnObject2.a = paramObject2.a;
return returnObject2;
}
As you can see above, both the function do the same task but they take different parameters as input and return different objects.
I would like to minimize writing different functions that does the same task.
Is it possible to write a generic method for this that can substitute the parameters based on the call to the function?
paramObject and returnObject are basically two classes that have different variables. They are not related to each other.
My objective is that I do not want to do function overloading since the functions do almost the same work. I would like to have a single function that can handle different input and different return output.
my aim is to do something like this (if possible):
public static < E > myfunction( T a, int a ) {
// do work
}
The return type E and the input T can keep varying.
you can using the 3rd apply method to remove the code duplications, you separate creation & initialization from the apply method in this approach. and don't care about which type of T is used. for example:
returnObject1 myfunction(paramObject1 a, int b) {
return apply(returnObject1::new, b, value -> {
//uses paramObject1
//populates returnObject1
//for example:
value.foo = a.bar;
});
}
returnOject2 myfunction(paramObject2 a, int b) {
return apply(returnOject2::new, b, value -> {
//uses paramObject2
//populates returnObject2
//for example:
value.key = a.value;
});
}
<T> T apply(Supplier<T> factory, int b, Consumer<T> initializer) {
T value = factory.get();
initializer.accept(value);
//does work ...
return value;
}
Note the 2 myfunction is optional, you can remove them from you source code, and call the apply method directly, for example:
paramObject2 a = ...;
returnObject2 result = apply(returnOject2::new, 2, value -> {
//for example:
value.key = a.value;
});
Make interface Foo and implement this interface in both paramObject1 and paramObject2 class. Now your method should be look like:
public Foo myFunction(Foo foo, int a){
//Rest of the code.
return foo;
}

How does method reference casting work?

public class Main {
interface Capitalizer {
public String capitalize(String name);
}
public String toUpperCase() {
return "ALLCAPS";
}
public static void main(String[] args) {
Capitalizer c = String::toUpperCase; //This works
c = Main::toUpperCase; //Compile error
}
}
Both are instance methods with same signature. Why does one work and the other doesn't?
Signature of String::toUpperCase: String toUpperCase();
There are 3 constructs to reference a method:
object::instanceMethod
Class::staticMethod
Class::instanceMethod
The line:
Capitalizer c = String::toUpperCase; //This works
use 3'rd construct - Class::instanceMethod. In this case first parameter becomes the target of the method. This construct is equivalent (translates) to following Lambda:
Capitalizer = (String x) -> x.toUpperCase();
This Lambda expression works because Lambda gets String as parameter and returns String result - as required by Capitalizer interface.
The line:
c = Main::toUpperCase; //Compile error
Translates to:
(Main m) -> m.toUpperCase();
Which does not work with the Capitalizer interface. You could verify this by changing Capitalizer to:
interface Capitalizer {
public String capitalize(Main name);
}
After this change Main::toUpperCase will compile.
You have a method which
public String capitalize(String name);
Takes a String and returns a String. Such a method can have a number of patterns.
A constructor
c = String::new; // calls new String(String)
// or
c = s -> new String(s);
A function on String which takes no arguments
c = String::toLowerCase; // instance method String::toLowerCase()
// or
c = s -> s.toLowerCase();
of a method which takes a String as the only argument
// method which takes a String, but not a Main
public static String toUpperCase(String str) {
c = Main::toUpperCase;
// or
c = s -> toUpperCase(s);
In every case, the method referenced has to take the String.
If not you can do this instead.
c = s -> capitalize(); // assuming Main.capitalize() is static
This tells the compiler to ignore the input.
You should change:
public String toUpperCase()
to
public static String toUpperCase(String text)
You should read the java tutorial on method references. The different kind of method references and there is a similar example with String::compareToIgnoreCase (Reference to an Instance Method of an Arbitrary Object of a Particular Type).
The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).

Categories