Related
Is it possible to do this in Java:
pass a parameter to a method which will accept list of different types
as well as use that Class type inside the method ?
public class Test {
public boolean testing(List<ClassType> testObjs) {
int vals = 0;
if (CollectionUtils.isNotEmpty(testObjs)) {
vals += testObjs.stream()
.map(ClassType::getTestType)
.filter(isTestobj::isTest)
.count();
}
do_processing_with_vals
return boolean_value;
}
}
There are 3 different classes which have method getTestType but unfortunately they are in different libraries and do not share a common parent class/Interface. I have to call a method (eg testing) which could take a list of either of these 3 class objects and do some processing with it. I do not want 3 different methods with only the difference being the class of the object that is passed (eg. ClassType).
When I use Object in place of ClassType, it throws error saying cannot resolve method getTestType.
Since the methods don't share a common interface (which is the best solution), the cleanest option may be to pass an appropriate Function or Predicate:
public boolean <T> testing(List<T> testObjs, Predicate<? super T> isTest) {
vals += testObjs.stream().filter(isTest).count();
}
...
testing(someObjs, ObjType::isTest);
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.
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 );
}
}
Assume I have the following functional interface:
public interface TemperatureObserver {
void react(BigDecimal t);
}
and then in another class an already filled-in ArrayList of objects of type TemperatureObserver.
Assuming that temp is a BigDecimal, I can invoke react in a loop using:
observers.forEach(item -> item.react(temp));
My question: can I use a method reference for the code above?
The following does not work:
observers.forEach(TemperatureObserver::react);
The error message is telling me that
forEach in the Arraylist observers is not applicable to the type TemperatureObserver::react
TemperatureObserver does not define a method react(TemperatureObserver)
Fair enough, as forEach expects as an argument a Consumer<? super TemperatureObserver>, and my interface, although functional, does not comply to Consumer because of the different argument of react (a BigDecimal in my case).
So can this be solved, or it is a case in which a lambda does not have a corresponding method reference?
There are three kinds of method references that can be used when a single value is available from the stream:
A parameter-less method of the streamed object.
class Observer {
public void act() {
// code here
}
}
observers.forEach(Observer::act);
observers.forEach(obs -> obs.act()); // equivalent lambda
The streamed object becomes the this object of the method.
A static method with the streamed object as parameter.
class Other {
public static void act(Observer o) {
// code here
}
}
observers.forEach(Other::act);
observers.forEach(obs -> Other.act(obs)); // equivalent lambda
A non-static method with the streamed object as parameter.
class Other {
void act(Observer o);
}
Other other = new Other();
observers.forEach(other::act);
observers.forEach(obs -> other.act(obs)); // equivalent lambda
There is also a constructor reference, but that is not really relevant to this question.
Since you have an external value temp, and you want to use a method reference, you can do the third option:
class Temp {
private final BigDecimal temp;
public Temp(BigDecimal temp) {
this.temp = temp;
}
public void apply(TemperatureObserver observer) {
observer.react(this.temp);
}
}
Temp tempObj = new Temp(temp);
observers.forEach(tempObj::apply);
Take a look at the Method References section in the Java Tutorial. There it says:
There are four kinds of method references:
Reference to a static method: ContainingClass::staticMethodName
Reference to an instance method of a particular object: containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type: ContainingType::methodName
Reference to a constructor: ClassName::new
There it explains that i.e. TemperatureObserver::react would be a method reference of the 3rd type: a reference to an instance method of an arbitrary object of a particular type. In the context of your call to the Stream.forEach method, that method reference would be equivalent to the following lambda expression:
(TemperatureObserver item) -> item.react()
Or just:
item -> item.react()
Which doesn't match your void TemperatureObserver.react(BigDecimal t) method signature.
As you already suspect, there are cases for which you can't find an equivalent method reference for a lambda. Lambdas are way more flexible, though IMHO sometimes they are less readable than method references (but this is a matter of taste, many people think the other way round).
A way to still use a method reference would be with a helper method:
public static <T, U> Consumer<? super T> consumingParam(
BiConsumer<? super T, ? super U> biConsumer,
U param) {
return t -> biConsumer.accept(t, param);
}
Which you could use as follows:
observers.forEach(consumingParam(TemperatureObserver::react, temp));
But, honestly, I prefer to use a lambda.
It does not works, because you iterate over handlers, not over parameters.
For example, this code works:
ArrayList<BigDecimal> temps = new ArrayList<>();
TemperatureObserver observer = new TemperatureObserverImpl();
temps.forEach(observer::react);
Is it possible to write an equivalent code in Java for the following swift code? In fact, I want to know if it's possible to have a case of functions inside Java's enum (X, Y in MyEnum)
enum MyEnum{
case X((Int) -> String)
case Y((Double) -> Int)
}
No, you can't; at least, not if you want the differing types to be available when you use the enum. All enum values have to have the same type.
When you want "enum" values to have heterogenous types, you could use a class with static final fields:
final class MyHeterogeneousEnum {
private MyHeterogeneousEnum() {} // Not instantiable.
static final Function<Integer, String> X = ...;
static final Function<Double, Integer> Y = ...;
}
which allows you to use the values with their full type information:
String s = MyHeterogeneousEnum.X.apply(123);
Integer i = MyHeterogeneousEnum.Y.apply(999.0);
Of course, you don't have useful methods like name(), or values() to iterate over the constants in this class, nor is it inherently serializable. You can make implement these yourself - but for values() you have to use wildcards in the return type, in order that all values can be returned:
static Iterable<Function<?, ?>> values() {
return Collections.unmodifiableList(Arrays.asList(X, Y));
}
However, note that a Function with a wildcard input type parameter is pretty much useless: you can't actually pass anything into it (other than null); so the values() method has limited utility.
It is possible (technically), but it might not be that useful, as creating a simple class, that consumes a Function instance.
As you might already know, in Java, the enums represent one or more constants of the same type, which could have their own properties - this include java.util.Function instances. However, these Function instances cannot be passed dynamically at Runtime, but should be rather set at compile time, so that the constant is created.
Of course, you could make each enum constant have a different typed Function, by just creating the enum's constructor Generic:
enum MyEnum {
X((String x) -> "Hello"), Y((Double d) -> 1);
Function<?, ?> function;
MyEnum(Function<?, ?> function) {
this.function = function;
}
}
This, however, is not quite useful (although it compiles just fine). The Function in X doesn't use it's String parameter and returns a fixed value. So does the one in Y.
I'd rather introduce two separate instances of the same class:
class Instance<T, U> {
private Function<T, U> function;
public Instance(Function<T, U> function) {
this.function = function;
}
}
This will allow you to dynamically pass a Function instance, instead of setting it at compile-time.
Yes for sure you can, in java enums can be more that just constants... every one of it values can be an anonymous class (take a look to TimeUnit.class for example)
now, you can do somthing like:
interface IFunction {
double getY(double x);
}
enum Function implements IFunction {
LINE {
#Override
public double getY(double x) {
return x;
}
},
SINE {
#Override
public double getY(double x) {
return Math.sin(x);
}
}
}
and then the implementation
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Function.LINE.getY(i));
System.out.println(Function.SINE.getY(i));
}
}