I've encountered the following code in a Java project, and I'm not sure what to make of it:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return ((Function<CustomEnum,String>) (someObject::toString)).andThen(r -> someObject::getSomethingWithEnumParameter);
}
I don't really understand how you can cast something to a Functional Interface. What does that even mean?
Isn't the resulting type of the return value going to be whatever value someObject.
Isn't Function<CustomEnum, String> defining an anonymous function that takes a type CustomEnum and returns a String?
I've read the java doc for Function<T,R>, and to be honest, this doesn't make much more sense than before I read the document.
This is what I believe is happening.
foo is returning an anonymous function that is applied to some CustomEnum to return a String
the anonymous function inside of foo (which is somehow cast onto someObject::toString, which I don't understand) is applied to the CustomEnum that will be passed from the initial call of foo(someObject).apply(customEnum).
The andThen will take the resulting String from the anonymous function inside of foo (which was cast somehow I still don't understand), and then return the value of someObject::getSomethingWithEnumParameter. Why isn't the return type just the type of someObject::getSomethingWithEnumParameter, which we'll say is a Map<R,T>, for sake of discussion.
If anyone could help me understand this flow, I would greatly appreciate it.
In an ideal world this would work:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return (someObject::toString).andThen(...);
}
However Java needs an interface type in order to implicitly create an interface instance from the method reference., hence the explicit cast is required to cast to the Function interface type.
Once you have an instance of Function then you can call any method on it as per normal, in this case the andThen method which composes it with another function object to form a new function.
Breaking it down:
someObject::toString is a method reference with implied type Function<CustomEnum, String>. I.e. toString is a method on SomeObject which takes a parameter of type CustomEnum and returns a String.
r -> someObject::getSomethingWithEnumParameter has the wrong type though - it's a function which returns a function. If you get rid of the "r ->" part then it is valid, as long as someObject::getSomethingWithEnumParameter is a method on SomeObject that takes a String and returns a String. Alternatively the return type of foo would need to change to Function<CustomEnum, Function<String, String>>.
If you combine those two with andThen then you have a Function which takes a CustomEnum and returns a String, as pr the return type of foo.
Related
I am trying to implement a Map<String, Interface> where the interface in question takes in and returns a generic value, so that different functions in the map could have different return types but still using the same interface. I'm not quite sure how it would work but the goal would be to achieve something along these lines below.
// A generic interface of some kind
public interface Action {
Object doAction(Object object);
}
// The class which implements the map
public class MyClass {
public void example() {
HashMap<String, Action> map = new HashMap<>();
// this takes in a boolean and returns the opposing value
map.put("functionOne", (boolean bool) -> !bool);
// this takes in an integer, increments it and returns it.
map.put("functionTwo", (int integer) -> integer++);
...
}
}
Obviously this pseudo code isn't right and I might be way off track but I hope it gives you an understanding of what I'm trying to achieve. Any help would be appreciated.
First of all, your interface should be declared as FunctionalInterface.
Second, since your doAction method takes Object as an argument, I see no point in returning it, unless you want to preserve the original object. You can just modify the object inside the method and make your method void. After invoking the method, your object, which was passed, will be modified. (you want to use objects like Int, Boolean and etc., which wrap up the primitive types)
But overall, this approach seems a little bit old styled and unreliable one. Since this will lead you to creating if statements to ensure you are operating the right type (As some of the colleagues have written in comments).
What I would do is to make Action generic.
#FunctionalInterface
public interface Action<T> {
T doAction(T argument);
}
Then just declare your functions like below and use them without creating a collection for them, because it will result in writing more code to ensure type-safety.
Action<Boolean> booleanFunc = (Boolean bool) -> {...};
In this example, passing a method reference to Stream.of does not work but once it's wrapped it works. I can't quite get my head around why this is. Isn't the method reference equivalent to the functional interface?
public class A {
String a() {
return "";
}
void b() {
Stream.of(this::a); // won't compile
Stream.of(wrap(this::a)); // will compile
}
static <T> Supplier<T> wrap(Supplier<T> f) {
return f;
}
}
Stream.of has the following signature:
public static<T> Stream<T> of(T t)
The following example will compile because you explicitly providing a type information for T.
Stream<Supplier<String>> a = Stream.of(this::a);
The first example Stream.of(this::a); equivalent to:
Object a = this::a;
where Object is not a functional interface and will not compile.
Providing with a functional interface this example compiles:
Runnable a = this::a;
Stream.of(a);
In the second example, wrap provides a functional interface Supplier
Stream.of(T) expects an Object and you pass to it a method reference in the first statement. But an Object parameter is not a functional interface, so it cannot accept a method reference or a lambda that is not specifically typed.
With lambda, it would produce also an error : Stream.of(()->this.a()).
A simpler example could be Stream.of(()-> "foo") that will just not compile.
But if you type the method reference or the lambda it works :
Stream.of((Supplier<String>) this::a)
or
Stream.of((Supplier<String>) () -> this.a())
In the working statement you pass to Stream.of(T) a parameter that is a Supplier<String>. That refers to a functional interface but that is typed as in the previous working examples, so it is valid as parameter that expects an Object.
this::a is contextless and could mean different things. You need to provide some context to help the compiler to figure out what you actually meant by this::a.
Stream.<Supplier<String>>of(this::a);
Though, that Stream<Supplier<String>> doesn't seem to be what you wanted. If you need a Stream<String>, use Stream.generate: no extra type information needed since the method takes a Supplier<T> (no ambiguity here).
Stream.generate(this::a);
On a side note, both statements expect you to save their results into variables. Defining variables of the right type often facilitates resolving such issues.
Stream<Supplier<String>> s1 = Stream.of(this::a);
Stream<String> s2 = Stream.generate(this::a);
All credit to #J-Alex and #Holger for their precious comments.
In my Java application I created methods that return Either<String, T> objects.
This is because in some places I invoke these methods as the parameter of (3rd party) methods that expect a String parameter as input.
While in other places I invoke these methods as the parameter of (3rd party) methods that expect some other parameter type (T) as input.
So depending on the place where I invoke the methods that I created, the code looks like:
their.thirdPartyExpectsString(my.calculateEither().getLeft());
their.thirdPartyExpectsString(my.calculateEither() + "");
or
their.thirdPartyExpectsDouble(my.calculateEither().getRight());
(I defined Either.toString() as Either.getLeft()).
Pay attention, I cannot change the 3rd party code (anyway not without bytecode manipulation), and I would like to keep my design in which I return Either from my methods.
Is there a way to simplify my code and make it look like
their.thirdPartyExpectsString(my.calculateEither());
their.thirdPartyExpectsDouble(my.calculateEither());
I.e., not having to add the getLeft()/getRight() or + "" all the time?
Actually, it does not bother me much if I will have to do
their.thirdPartyExpectsDouble(my.calculateEither().getRight());
because I don't have to do it often. But I would like to get rid of the need to call getLeft() or + "" when my.calculateEither() returns a Left (a String).
Given an either, it's not hard to see if it represents Right or Left, simply by checking which side has a null.
But the problem is with the type conversion, i.e. the compilation error when thirdPartyExpectsString() expects a String but gets an Either.
I was able to catch the return value of my.calculateEither() by AspectJ but I could not see a way how to use something like #AfterReturning advice to make the compiler understand that I want to return my.calculateEither().getLeft(), i.e a String....
Any ideas?
Add the following method to your implementation of the Either class:
#SuppressWarnings("unchecked")
public <T> T whichever() {
return (T) (isLeft() ? getLeft() : getRight());
}
Note that I'm purposefully ignoring the warning about the unchecked cast, and indeed will cause a ClassCastException if you use it in a place where the external API you interface with expects a left value but you invoke it on an Either instance which contains a right value. This method will do an implicit cast based on where you use it. It will cast to a T type where you pass it to another method which expects an argument of type T or you try to assign the method return value to a variable of type T.
So the following demo code:
Either<String, Double> containsString = Either.<String, Double>left("first");
Either<String, Double> containsDouble = Either.<String, Double>right(2d);
their.expectsString(containsString.whichever());
their.expectsDouble(containsDouble.whichever());
their.expectsDouble(containsString.whichever());
will work well in the first invocation and will cause a ClassCastException in the third invocation, just an one would expect, because we consider it as an illegal use case.
In conclusion, it's nice to know that it will work in all places where the T type to which we are implicitly casting is assignable to the actual value contained by the Either object. Unfortunately, you will only find out at run time, should this not be the case.
Add a helper method. Since you cannot add new methods to their, you have to add a static to a class of your own.
Pseudo-code:
public static void thirdParty(Their their, Either either) {
if (either.isLeft())
their.thirdPartyExpectsString(either.getLeft());
else
their.thirdPartyExpectsDouble(either.getRight());
}
You can now call:
MyHelper.thirdParty(their, my.calculateEither())
Here is the method I am calling:
public static <T extends Something> Group<T> getGroup() { ... }
If I wanted to store the result in a variable, I would do something like this:
Group<SomethingSubClass> group = StaticClass.getGroup();
How would I call the method without storing it in a variable?
StaticClass.getGroup();
The above is what I tried, but I am unsure (mostly don't think it is possible from the way my method is) to add the generic type T.
Solution:
StaticClass.<SomethingSubClass>getGroup();
You don't need anything special. Just invoke it as
StaticClass.getGroup();
You will simply be ignore the return value. The type argument will be inferred as Something, which is what you'd have access to in your method anyway.
You would specify an actual type argument by doing
StaticClass.<SomeTypeThatExtendsSomething>getGroup();
but you don't need that since the only part of your method that makes use of the generic type is the return type, which you are discarding.
I am still experimenting with how Java handles generics. I stumbled upon the fact/issue/thing that if you have a generic interface like A<T>, you cannot really check afterwards if some object is actually implementing A<B> or A<C>.
I wondered if that could cause actual problems.
Now I have tried this code:
static interface A<T> { void foo(T obj); }
static class B implements A<B> {
public void foo(B obj) { obj.bar(); }
void bar() {}
}
static {
assert (new B() instanceof A<?>);
((A<?>) new B()).foo(new Object());
}
This gives me this error (for the foo-call):
The method foo(capture#1-of ?) in the type Main.A<capture#1-of ?> is not applicable for the arguments (Object)
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A<?> is foo(? obj) which I thought is the same as foo(Object obj).
The assert succeeds.
What I tried to figure out is at what point exactly does it cast the object when I call the foo function.
Also, how can I call foo from A<?>? This is the thing I actually need to be able to do. Or is that impossible with any other parameter than null?
A more real-world example where I actually wonder about this: I use the Comparable<T> interface a lot. That case is actually even more complicated; I might open another question about that if this here doesn't answer it.
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A is foo(? obj) which I thought is the same as foo(Object obj).
Nope, absolutely not. Imagine A<T> is List<T> with foo(T) being add(T) and so A<?> is List<?>. Should you be able to do this?
List<String> strList = new ArrayList<String>();
List<?> wcList = strList;
wcList.add(Integer.valueOf(6)); //possible if add(?) is same as add(Object)
//...
String str = strList.get(0);
Of course not, since you'd get a ClassCastException in the final line.
What foo(?) really means is that the method applies to some unknown but specific type. You can't typically invoke these methods unless you pass null as the parameter, which is acceptable to assign to any reference type.
If you have "foo(? obj)" then the ? could be any type. If it is say String then you can't pass, say, an Integer to it. All you can pass is null.
Casting and use of instanceof should normally be avoided unless unavoidable (such as implementing equals), particularly with generics.
The compiler is correct because it does a compile-cast test on compile-time.
((A<?>) new B()).foo(new Object());
is errornous because the compiler expected
((A<?>) new B()).foo(A object)....
meaning that it wanted anything of type A or its children. Object is the parent of A and it doesn't match the compile-test Parameter type for compilation.
When you check if an instance of B is an instance of A<?> you just do the same thing as new B() instanceof A. You don't really check how T is set, it's just "something".
Later in the code with the cast, you tell that you'll use B as a A<?> so the variable will have the characteristic of a A but the generic type is still "something". This "something" exists and is probably a specified class but your don't care of the exact type.
That's why when you use the foo() method which take a T in parameter, you can't pass a "something" in parameter, because you don't know what it is, it could be an Object but it could be anything else.
Because of this the compiler tells you foo(capture#1-of ?) isn't applicable for the argument Object. The needed parameter is "something" but not necessarily an Object.
Then, when would you need this feature ?
For example if you work with a map, if you don't really care of the type of the key (if you only work with the values() method for example), you could do something like this :
Map<?, V> m
This way you won't be able to use features related to the key of the map (but you don't care about that), but you'll be able to use a map with any kind of key.
No, foo(? obj) is not actually the same as foo(Object obj). The difference is, when the parameter type is Object, it's explicitly stating that any type of object is legal. With a parameter type of ?, the method states that it does not know what type of object is legal... therefore nothing is legal except for null.
The reasoning for this becomes apparent when you consider a List rather than an arbitrary interface. Look at this method:
public void foo(List<?> list) {
list.add(...); // what can we add here?
}
The ? indicates that any type of List is acceptable... the List passed in could be a List<String>, a List<Integer> or a List<Map<Foo, Bar>>. There's no way of knowing. Note that this is only a problem with methods that consume generic parameters, such as add or your foo method. For methods that produce (return) an object of the generic type, it's fine to use such a method and assign the result as an Object. This, unlike the consumer method, cannot corrupt the internal state of the generic object.
Also notice that when you call ((A<?>) new B()).foo(new Object()), you're trying to do something illegal... if something (such as the Object) that is not a B were to be passed to B's foo method, it would explode at runtime. The compiler is correctly preventing you from doing this.
You may also want to check out my answer to another question here which explains some things about bounded wildcard types and such.
This is a simple explanation:
A<?> means A of unknown parametrized type. Given
A<?> ref = new B()
ref could point to any A: A<Object, A<String>, anything. So you can not call A.foo(new Object()) because in case of A<?> reference there is no way to know which parameter ref.foo() accepts. Actually the only thing valid is ref.foo(null).
Many have clarified that point about ? but noone has really answered the main question yet, so here it is:
It is possible to call A#foo like this:
((A) new B()).foo(new Object());
The cast then is done inside of foo.