Generic function as functional interface? - java

I have the following function which returns an List of the same type as which it is passed.
<T> List<T> foo(T bar)
{
...
}
I want to have this same function, except in the form of a Java Functional Interface. I've tried the following:
final <T> Function<T, List<T>> foo;
But it does not like the <T>. If I omit <T> like:
final Function<T, List<T>> foo;
It claims it cannot find type T, exactly the same error as if I were to define the original function as:
List<T> foo(T bar) // cannot find type 'T'
{
...
}
I want to have function foo as a first class function.

You’re confusing a method with a class, which may be implemented as a lambda.
If T isn’t a type in the context of the code, you can’t type anything.
You can do this:
class MyClass<T> implements Function<T, List<T>> {
public List<T> accept(T t) {
// some impl
}
}

Related

Generic bounded argument is incompatible with itself

I'm trying to create a generic method that accepts two typed arguments, one of them bounded by itself,
class Foo
{
<T extends Foo, V> void myself(final Optional<V> value, final BiConsumer<T, V> destination)
{
if (value.isPresent())
{
destination.accept(~~this~~, value.get());
}
}
}
but compiler blames on the this argument, because
error: incompatible types: Foo cannot be converted to T
destination.accept(this, value.get());
^
where T,V are type-variables:
T extends Foo declared in method <T,V>myself(Optional<V>,BiConsumer<T,V>)
V extends Object declared in method <T,V>myself(Optional<V>,BiConsumer<T,V>)
If T is a subtype of Foo, is clear that Foo is not for sure an instance of T.
But this being an extended of Foo, still is Foo.
Forcing the (T) this cast seems to ""work"".
Update
I want to use it the following way,
class Bar extends Foo
{
void setAnswer(Integer toLife)
{
}
}
----
void outThere(Bar bar)
{
bar.myself(Optional.of(42), Bar::setAnswer);
}
The proposal of wildcarded argument
class Foo
{
<V> void myself(final Optional<V> value, final BiConsumer<? super Foo, V> destination)
{
if (value.isPresent())
{
destination.accept(this, value.get());
}
}
}
fails on the usage with,
error: incompatible types: invalid method reference
bar.myself(Optional.of(42), Bar::setAnswer);
^
method setAnswer in class Bar cannot be applied to given types
required: Integer
found: Foo,V
reason: actual and formal argument lists differ in length
where V is a type-variable:
V extends Object declared in method <V>myself(Optional<V>,BiConsumer<? super Foo,V>)
T extends Foo
It's bounded by Foo, but it isn't necessarily actually Foo. It could be any subtype of Foo instead.
Instead of defining a type variable, use a wildcard:
final BiConsumer<? super Foo, V> destination
Also, a better way to write the method body is:
value.ifPresent(consumer);
(There isn't really much advantage in invoking your method over just doing this directly).
Update for your update:
If you want to express something resembling a self type, you need to add another type variable to the class:
class Foo<F extends Foo<F>>
{
<V> void myself(final Optional<V> value, final BiConsumer<? super F, V> destination) {
if (value.isPresent())
{
// (F) is an unchecked cast, but is necessary, because
// nothing constrains F to actually be "itself".
destination.accept((F) this, value.get());
}
}
Then the Bar class is defined as:
class Bar extends Foo<Bar> {
void setAnswer(Integer toLife) { /* ... */ }
}
Then the outThere method works fine:
void outThere(Bar bar)
{
bar.myself(Optional.of(42), Bar::setAnswer);
}
Ideone demo
Let's say, Foo has two subclasses, Foo1 and Foo2, both not overriding the myself() method. Then:
Foo1 me = ...;
Optional<String> value = ...
BiConsumer<Foo2,String> consumer = ...;
me.myself(value, consumer);
matches
<T extends Foo, V> void myself(final Optional<V> value, final BiConsumer<T, V> destination) {...}
with V being String and T being Foo2, while this is of class Foo1, so you can't pass it into a Foo2 consumer.
And that's what the compiler detected.
The problem is that there is no guarantee that your T is compatible with this.
It could that the BiConsumer is referring to a something that extends T, then T would not fit in. The issue is that you are inferring T and that might not be compatible with this.
If you really want this, then you should remove T all together and just use Foo.
If you want anything that extends Foo and wishes to infer that, then you could use super instead.
<V> void myself(final Optional<V> value, final BiConsumer<? super Foo, V> destination) {
if ( value.isPresent() ) {
destination.accept(this, value.get());
}
}
You are going to find some issues with this approach though.
Otherwise, you could also use Foo directly as mentioned:
public static class Foo {
<T, V> void myself(final Optional<V> value, final BiConsumer<Foo, V> destination) {
if ( value.isPresent() ) {
destination.accept(this, value.get());
}
}
}
Otherwise, if you are really sure you could cast it, but that is not really recommended.

Consumer<T> mapped Class<T> in HashMap

I want to create an IdentityHashMap<Class<T>, Consumer<T>>. Basically, I want to map a type with a method saying what to do with this type.
I want to dynamically be able to say with objects X, execute Y. I can do
private IdentityHashMap<Class<?>, Consumer<?>> interceptor = new IdentityHashMap<>();
but it sucks because then I have to cast the object in the lamba when using it.
Example:
interceptor.put(Train.class, train -> {
System.out.println(((Train)train).getSpeed());
});
What I would like to do is
private <T> IdentityHashMap<Class<T>, Consumer<T>> interceptor = new IdentityHashMap<>();
But it doesn't seem to be allowed. Is there a way to do this ? What is the best workaround to map types with a method for this type ?
This is essentially just like the type-safe heterogeneous container described by Joshua Bloch, except you can't use the Class to cast the result.
Weirdly, I can't find a great example existing on SO, so here is one:
package mcve;
import java.util.*;
import java.util.function.*;
class ClassToConsumerMap {
private final Map<Class<?>, Consumer<?>> map =
new HashMap<>();
#SuppressWarnings("unchecked")
public <T> Consumer<? super T> put(Class<T> key, Consumer<? super T> c) {
return (Consumer<? super T>) map.put(key, c);
}
#SuppressWarnings("unchecked")
public <T> Consumer<? super T> get(Class<T> key) {
return (Consumer<? super T>) map.get(key);
}
}
That's type-safe, because the relation between keys and values is enforced by the signature of the put method.
One annoying thing about the limitations of Java's generics is that one of these containers can't be written for a generic value type, because there's no way to do e.g.:
class ClassToGenericValueMap<V> {
...
public <T> V<T> put(Class<T> key, V<T> val) {...}
public <T> V<T> get(Class<T> key) {...}
}
Other notes:
I would use a regular HashMap or a LinkedHashMap for this. HashMap is better maintained and has many optimizations that IdentityHashMap doesn't have.
If it's necessary to use generic types, like Consumer<List<String>>, then you need to use something like Guava TypeToken as the key, because Class can only represent the erasure of a type.
Guava has a ClassToInstanceMap for when you need a Map<Class<T>, T>.
Sometimes people want to do something like this, with a class-to-consumer map:
public <T> void accept(T obj) {
Consumer<? super T> c = get(obj.getClass());
if (c != null)
c.accept(obj);
}
That is, given any object, find the consumer in the map bound to that object's class and pass the object to the consumer's accept method.
That example won't compile, though, because getClass() is actually specified to return a Class<? extends |T|>, where |T| means the erasure of T. (See JLS §4.3.2.) In the above example, the erasure of T is Object, so obj.getClass() returns a plain Class<?>.
This issue can be solved with a capturing helper method:
public void accept(Object obj) {
accept(obj.getClass(), obj);
}
private <T> void accept(Class<T> key, Object obj) {
Consumer<? super T> c = get(key);
if (c != null)
c.accept(key.cast(obj));
}
Also, if you want a modified version of get which returns any applicable consumer, you could use something like this:
public <T> Consumer<? super T> findApplicable(Class<T> key) {
Consumer<? super T> c = get(key);
if (c == null) {
for (Map.Entry<Class<?>, Consumer<?>> e : map.entrySet()) {
if (e.getKey().isAssignableFrom(key)) {
#SuppressWarnings("unchecked")
Consumer<? super T> value =
(Consumer<? super T>) e.getValue();
c = value;
break;
}
}
}
return c;
}
That lets us put general supertype consumers in the map, like this:
ctcm.put(Object.class, System.out::println);
And then retrieve with a subtype class:
Consumer<? super String> c = ctcm.findApplicable(String.class);
c.accept("hello world");
Here's a slightly more general example, this time using UnaryOperator and no bounded wildcards:
package mcve;
import java.util.*;
import java.util.function.*;
public class ClassToUnaryOpMap {
private final Map<Class<?>, UnaryOperator<?>> map =
new HashMap<>();
#SuppressWarnings("unchecked")
public <T> UnaryOperator<T> put(Class<T> key, UnaryOperator<T> op) {
return (UnaryOperator<T>) map.put(key, op);
}
#SuppressWarnings("unchecked")
public <T> UnaryOperator<T> get(Class<T> key) {
return (UnaryOperator<T>) map.get(key);
}
}
The ? super bounded wildcard in the first example is specific to consumers, and I thought an example without wildcards might be easier to read.
It is possible to implement this in a type-safe manner without any unchecked cast. The solution resides in wrapping the Consumer<T> into a more general Consumer<Object> that casts and then delegates to the original consumer:
public class ClassToConsumerMap {
private final Map<Class<?>, Consumer<Object>> map = new IdentityHashMap<>();
public <T> Consumer<? super T> put(Class<T> key, Consumer<? super T> c) {
return map.put(key, o -> c.accept(key.cast(o)));
}
public <T> Consumer<? super T> get(Class<T> key) {
return map.get(key);
}
}
Depending on your needs, get() could also simply return a Consumer<Object>. This would be necessary if you only know the type at runtime, e.g.
classToConsumerMap.get(someObject.getClass()).accept(someObject);
I am pretty sure I saw this solution (or something similar) in a talk # Devoxx Belgium 2016, possibly from Venkat Subramaniam, but I definitively cannot find it back…
I can just let the IdentityHashMap with the usual Class<?> and Consumer<?>
private IdentityHashMap<Class<?>, Consumer<?>> interceptor = new IdentityHashMap<>();
And then I wrap the put operation in a method. This method accepts a type and a consumer of the same generic.
public <T> void intercept(Class<T> type, Consumer<T> consumer)
{
interceptor.put(type, consumer);
}
This lets me write
intercept(Train.class, train -> {
System.out.println(train.getSpeed());
});

How to pass bounded generic type parameter class as argument

how do you get class name of type parameter object?
Example: if function is
public <T extends Base> void convert(final T arg) {}
public <T> void method2(Class<T> typeParamClass) {}
How do i pass arg as Class<T> to method 2?
Error message when i try to pass arg.getClass()
Real Code Snippet
static <T> byte[] method2(T object, final Class<T> typeParameterClass) throws SerializationException {
}
static <T> T method3(final byte[] serializedObject, final Class<T> typeParameterClass) throws SerializationException {
return (T) serializer.deserialize(typeParameterClass, Buffers.toBuffer(serializedObject));
}
}
public static <T> T clone(final T object) {
return method3(method2(object, object.getClass()), object.getClass());
}
public <T> void method2(Class<T> typeParamClass)
If you make the second method generic, you will be able to invoke that like
public <T extends Base> void convert(final T arg) {
method2(arg.getClass());
}
There are no restrictions for T in the method2 (T extends Object), so you are free to pass any T (including T extends Base).
As Sotirios Delimanolis noted, T is really meaningless here and the method can be defined simply:
public void method2(Class<?> typeParamClass)
UPDATE:
method2(object, object.getClass())
^^^
The main issue here is that getClass() is a virtual method, returns a runtime type of an instance. It can not guarantee to return a Class<T> from the given T, but ? extends T it can. To make it compiles, you have to change the signature to:
method2(T object, final Class<? extends T> typeParameterClass)
^^^
As mentioned in the answer from Andrew, the problem is the type erasure.
You are working with generics, getClass on T yields Class<?>, not Class<T>.
However, since we know that the type of T will always be Class<T>,
you can cast object.getClass to Class<T>, so you don't have to alter the method signature with redundant parameters.
So you could write:
public static <T> T clone(final T object) {
#SuppressWarnings("unchecked") // The type of 'object' will always be 'T'
Class<T> typeClass = (Class<T>) object.getClass();
return method3(method2(object, typeClass), typeClass);
}

How to understand the Java doc syntax

For example, I see
static <T extends Comparable<? super T>> void parallelSort(T[] a)
Sorts the specified array of objects into
ascending order, according to the natural ordering of its elements.
So I get this is a static method and what it does, but what does <T extends Comparable<? super T>> mean (return type, but what is it, is it the same way I would write in the code, or a syntax used in the documentation to show several possible values)
<T extends Comparable<? super T>> is not the return type. void is the return type. A generic specification before the return type is for type inference.
The argument (T[]) type is inferred from the call, and must be something that extends Comparable<? super T>
Suppose you have a class defined:
class Foo extends Comparable<Foo> { ... }
That means:
Foo[] fooArray = ...
parallelSort(fooArray);
is legal, and inside the parallelSort() method, T will be of type Foo (which implements the Comparable interface)
Here's a simple, less complicated example without the recursive type. In this case, it says it returns a list of the inferred type:
public static <T> <List<T>> myMethod(T arg) {
List<T> list = new ArrayList<T>();
list.add(arg);
return list;
}
The type is inferred from the argument:
List<String> list = myMethod("hi");

In generic method <T> doSth(List<T> l), check whether T implements Comparable?

The title basically says it all: if I have a java method that is generic in T, can I find out anything about T? In particular, can I check whether T implements a certain interface or extends a certain class?
I would like to do something like
public <T> List<T> doSth(List<T> l) {
if(T extends Comparable) {
// do one thing
} else {
// do another
}
return l;
}
Any hints?
Thanks a lot,
Johannes
It's not clear whether you want to perform the check at compile-time or at runtime. If you simply want to ensure that the list parameter passed to the method contains certain types of objects, then redefine T appropriately.
For example, to ensure that the compiler will only allow a List<Comparable> to be passed to this method, redefine T as:
public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
// Method body omitted
}
You can then use method-overloading (instead of an if-else statement), to ensure the correct code is called for any value of T. In other words, replace this:
public <T> List<T> doSth(List<T> l) {
if(T extends Comparable) {
// do one thing
} else {
// do another
}
return null
}
with these:
public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
// do one thing
return null;
}
public <T> List<T> doSth(List<T> l, Class<T> clazz) {
// do another
return null;
}
However, you need to remember choosing which overloaded method to call and generic-type checking is compile-time only! For example, the following code:
List<? extends Serializable> alist = new ArrayList<Integer>();
doSth(alist);
will actually call the second doSth method, because the compile-time type parameter (? extends Serializable) does not implement Comparable, even though the runtime type parameter (Integer) does.
No - due to type erasure. At execution time, you don't know the type of T at all.
One option would be to specify the type as another parameter:
public <T> List<T> doSth(List<T> l, Class<T> clazz) {
if (Comparable.class.isAssignableFrom(clazz)) {
...
}
}
yes, you can:
public <T> List<T> doSth(List<T> l) {
//You could also check every element, if there is a chance only some will be comparable
if (l.size() >0 && l.get(0) instanceof Comparable) {
// do one thing
} else {
// do another
}
return l;
}
Note that you are checking what type the elements in "l" are, NOT T - that is the key.
Edit: Changed the code to handle the fact that it was a list - I had missed that in my original reading.
You should already know at (even before! :) compile time whether T extends Comparable or not, so why not make two methods?
public <T extends Comparable<T>> List<T> doSthComp(List<T> l) {
// do one thing
return l;
}
public <T> List<T> doSth(List<T> l) {
// do another
return l;
}
You can do a
public <T extends Comparable<T>> List<T> doSth(List<T> l)
which will allow you to use the Comparable interface on items in 'l'
Well for compile time check Don already gave an answer. For the runtime it's only possible if you also pass a explicit object representing T, for example:
static <T> List<T> doSth(List<T> l, Class<T> tClass)
having tClass object representing real class of T you can check if it have implemented comparable via reflection. But compile-time check is much, much better from my point of view.

Categories

Resources