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());
});
Related
I'm playing around with predefined Identity filters for use with the stream api. Unfortunately I'm unable to properly return a generic predicate that is compliant with the stream api documentation.
According to the de-compiler here is the Stream::filter definition:
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> var1);
I'm facing the issue with any Java version that has Streams support (8~15). The issue has nothing to do with my implementation. This code actually is enough in order to reproduce it:
Collection<String> result = Stream.of("A", "B", "C")
.filter(new Object()::equals)
.filter(Integer.valueOf(-1)::equals)
.collect(Collectors.toSet());
Here, two predicates are applied where both of them aren't <? super String> compliant...
According to this answer this behavior seems to be strange...
How should I prevent users of my library from filtering on ServerState by random Object equality check, etc...?
Ideally I would like to always return proper Predicate<? super T> unfortunately that is not backed up by any compile time error...
Using a linter is not a solution in that case.
Even though I know how lower bounded wildcards work what I've been missing is that a Predicate<? super Integer> could be successfully casted to Predicate<? super String>.
Where:
Predicate<? super String> stringPredicate = (Predicate<? super String>)Filters.is_tClass(Integer.class, 4);
Predicate<? super Server> serverPredicate = (Predicate<? super Server>)Filters.is_comparable(5);
Collection<Integer> result = Stream.of(1, 2, 3)
.filter((Predicate<? super Integer>)stringPredicate)
.filter((Predicate<? super Integer>)serverPredicate)
.filter(Filters.is(new Object()))
.collect(Collectors.toSet());
results in [] empty resultset.
Here is what I have so far, but not happy with any of it:
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Collection<Integer> result = Stream.of(1, 2, 3)
//.filter(Filters.is_tClass(Integer.class, 4)) // enforce user to provide target class
//.filter(Filters.is_comparable(5)) // use only Comparable
.filter(Filters.is(new Server())) // fail runtime with custom exception
.collect(Collectors.toSet());
System.out.println(result);
}
private static class Server {
}
private static class Filters {
private static <T> Predicate<? super T> is(T other) {
return t -> {
// simple class equality check - error prone!
Class<?> tClass = t.getClass();
Class<?> otherClass = other.getClass();
if (!tClass.equals(otherClass)) {
throw new RuntimeException(
String.format("Check equality for [%s ? %s] seems odd. Can not continue...", tClass, otherClass));
}
return t.equals(other);
};
}
static <T> Predicate<? super T> is_tClass(Class<T> tClass, T other) {
return is(other);
}
static <T extends Comparable<T>> Predicate<? super T> is_comparable(T other) {
return is(other);
}
}
}
Methods with names of the type is_* did not exist before posting the sample in here and therefor will be removed...
EDIT
Even though I know how lower bounded wildcards work what I've been missing is that a Predicate<? super Integer> could be successfully casted to Predicate<? super String>.
Where:
Predicate<? super String> stringPredicate = (Predicate<? super String>)Filters.is_tClass(Integer.class, 4);
Predicate<? super Server> serverPredicate = (Predicate<? super Server>)Filters.is_comparable(5);
Collection<Integer> result = Stream.of(1, 2, 3)
.filter((Predicate<? super Integer>)stringPredicate)
.filter((Predicate<? super Integer>)serverPredicate)
.filter(Filters.is(new Object()))
.collect(Collectors.toSet());
results in [] empty resultset.
Here, two predicates are applied where both of them aren't <? super String> compliant
It's not true: the 2 predicates do consume an Object, which is the parent of String.
<? super String> must not be confused with <? extends String>.
I'm looking for a "proper" way to reduce the Java boilerplate involved in retrieving/modifying the generic type arguments at compile time. Usually, this boilerplate involves:
Using #SuppressWarnings("unchecked").
Spelling out explicitly the target generic type arguments.
Usually, creating an otherwise useless local variable just so that the supression can be applied to that staement only.
As a theoretical example, suppose I want to keep a map of Class to Supplier such that for each keyClass, its associated valueSupplier produces objects extending keyClass.
Edit 2: I changed the example from a map of Class to Class, to a map of Class to Supplier, because (the value) Class objects are special with respect to casts, and the original example had another solution not involving unchecked casts (thanks #Holger). Again, I'm only adding an example to illustrate the problem, I don't need to solve any particular example.
Edit 1: More precisely, a single SupplierMap object is populated say from a config file, and holds info such as "objects implementing interface I1 are provided by supplier S1", "I2 by S2", and so on. At runtime, we get calls such as I1 i1 = supplierMap.get(I1.class).get() which should produce an object with i1.getClass() == C1.class. I'm not interested in fixes/shortcuts, e.g. moving the cast to where it does not belong, such as having get() return Supplier<Object>. The cast belongs conceptually inside the SupplierMap. Also, I don't much care about this specific example, but about the general language problem.
With SupplierMap, I don't believe there is a way to capture the key-value generic parameter relation in Java so that the get() does not involve an unchecked compile-time cast. Concretely I could have:
class SupplierMap {
// no way to say in Java that keys and values are related
Map<Class<?>, Supplier<?>> map;
// can check the relation at compile time for put()
<T> void put(Class<T> keyClass, Supplier<? extends T> valueSupplier) {
map.put(keyClass, valueSupplier);
}
// but not for get()
<T> Supplier<? extends T> get(Class<T> keyClass) {
#SuppressWarnings("unchecked")
final Supplier<? extends T> castValueSupplier = (Supplier<? extends T>) map.get(keyClass);
return castValueSupplier;
}
}
As an alternative, one could have:
#SupressWarnings("unchecked")
<T> T uncheckedCast(Object o) {
return (T) o;
}
<T> Supplier<? extends T> get(Class<T> keyClass) {
return uncheckedCast(map.get(keyClass));
}
That looks much better, but the problem is that uncheckedCast is arguably too powerful: it can potentially cast anything into anything else at compile time (by hiding warnings). At runtime we'd still get CCE's, but that's not the point here. (The argument goes that ...) If one were to put this uncheckedCast into a library, the function could be abused to hide problems otherwise detectable at compile-time.
Is there a way to define such a similar unchecked cast function so that the compiler can enforce that it is only used to change generic type parameters?
I tried:
// error at T<U>: T does not have type parameters
<T, U> T<U> uncheckedCast(T t) {
return (T<U>) t;
}
also
<T, U extends T> U uncheckedCast(T t) {
return (U) t;
}
void test() {
Class<?> aClass = String.class;
// dumb thing to do, but illustrates cast error:
// type U has incompatible bounds: Class<capture of ?> and Class<Integer>
Class<Integer> iClass = uncheckedCast(aClass);
}
Edit: Have you seen this kind of an unchecked cast (even the all-powerful one above) in a common library? I looked in Commons Lang and Guava, but the only one I could find is Chronicle Core's ObjectUtils.convertTo(): there, passing eClass == null is equivalent to the all-powerful uncheckedCast, except that it also produces an undesired #Nullable (that is used by other branches).
You said
Also, I don't much care about this specific example, but about the general language problem.
but actually, this kind of problem should always be handled in relation to the actual problem you’re trying to solve. I’d go that far to say that this happens rarely enough, so a general utility method for doing unchecked casts regardless of the actual use case would not be justified.
Considering the SupplierMap, you said
I don't believe there is a way to capture the key-value generic parameter relation in Java so that the get() does not involve an unchecked compile-time cast.
That’s nailing the problem and pointing to the clean solution. You have to create a relationship between the key and value, e.g.
class SupplierMap {
static final class SupplierHolder<T> {
final Class<T> keyClass;
final Supplier<? extends T> valueSupplier;
SupplierHolder(Class<T> keyClass, Supplier<? extends T> valueSupplier) {
this.keyClass = keyClass;
this.valueSupplier = valueSupplier;
}
#SuppressWarnings("unchecked") // does check inside the method
<U> SupplierHolder<U> cast(Class<U> type) {
if(type != keyClass) throw new ClassCastException();
return (SupplierHolder<U>)this;
}
}
Map<Class<?>, SupplierHolder<?>> map = new HashMap<>();
<T> void put(Class<T> keyClass, Supplier<? extends T> valueSupplier) {
map.put(keyClass, new SupplierHolder<>(keyClass, valueSupplier));
}
<T> Supplier<? extends T> get(Class<T> keyClass) {
return map.get(keyClass).cast(keyClass).valueSupplier;
}
}
Here, the unchecked type cast is inside a method that performs an actual check allowing the reader to be confident about the correctness of the operation.
That’s a pattern that is actually used in real life code. Which hopefully addresses your question “Have you seen this kind of an unchecked cast (even the all-powerful one above) in a common library?”. I don’t think that any library uses a “do-entirely-unchecked” method, but rather, they have methods with a visibility as narrow as possible and likely tailored to the actual use case.
Yes, that means “boilerplate”. Which is not bad for an operation that the developer should really spend some seconds, before proceeding.
Note that this can be expanded to examples completely working without using Class as token:
interface SomeKey<T> {}
class SupplierMap {
static final class SupplierHolder<T> {
final SomeKey<T> keyClass;
final Supplier<? extends T> valueSupplier;
SupplierHolder(SomeKey<T> keyToken, Supplier<? extends T> valueSupplier) {
this.keyClass = keyToken;
this.valueSupplier = valueSupplier;
}
#SuppressWarnings("unchecked") // does check inside the method
<U> SupplierHolder<U> cast(SomeKey<U> type) {
if(type != keyClass) throw new ClassCastException();
return (SupplierHolder<U>)this;
}
}
Map<SomeKey<?>, SupplierHolder<?>> map = new HashMap<>();
<T> void put(SomeKey<T> keyClass, Supplier<? extends T> valueSupplier) {
map.put(keyClass, new SupplierHolder<>(keyClass, valueSupplier));
}
<T> Supplier<? extends T> get(SomeKey<T> keyClass) {
return map.get(keyClass).cast(keyClass).valueSupplier;
}
}
Which allows more than one key with the same type:
enum MyStringKeys implements SomeKey<String> {
SAY_HELLO, SAY_GOODBYE
}
public static void main(String[] args) {
SupplierMap m = new SupplierMap();
m.put(MyStringKeys.SAY_HELLO, () -> "Guten Tag");
m.put(MyStringKeys.SAY_GOODBYE, () -> "Auf Wiedersehen");
System.out.println(m.get(MyStringKeys.SAY_HELLO).get());
Supplier<? extends String> s = m.get(MyStringKeys.SAY_GOODBYE);
String str = s.get();
System.out.println(str);
}
The crucial part is that the now-unavoidable unchecked cast is still augmented with an actual check for the key validity. I’d never allow it without.
This doesn’t preclude scenarios where you really can’t check the correctness at all. But then, it is a good think that verbose artifacts like the #SuppressWarnings("unchecked") annotation indicate this right at the point where it is needed. A convenience method would only hide the problem, which is still there, even if we had a possibility to restrict its usage to generic types.
Answer to the previous revision of the question:
That’s actually easier than you think:
class ImplMap {
Map<Class<?>, Class<?>> map;
<T> void put(Class<T> keyClass, Class<? extends T> valueClass) {
map.put(keyClass, valueClass);
}
<T> Class<? extends T> get(Class<T> keyClass) {
final Class<?> implClass = map.get(keyClass);
return implClass.asSubclass(keyClass);
}
}
This is not an unchecked operation, as the method asSubclass really checks whether the implClass class is a subclass of keyClass. Assuming that the map has been populated via the put method only, without any unchecked operations, this test will never fail.
The only thing that differs, is the treatment of null, e.g. when the key was not present in the map. Unlike a cast, this would throw an exception, as it is a method invocation.
So if calling this method with absent keys is allowed and should result in null, it must be handled explicitly:
<T> Class<? extends T> get(Class<T> keyClass) {
final Class<?> implClass = map.get(keyClass);
return implClass == null? null: implClass.asSubclass(keyClass);
}
Note that likewise, the method
#SupressWarnings("unchecked")
<T> T uncheckedCast(Object o) {
return (T) o;
}
is unnecessary if you have the Class object, as then, you can invoke cast on it.
E.g., the following would be a valid addition to your ImplMap class:
<T> T getInstance(Class<T> keyClass) {
try {
return keyClass.cast(map.get(keyClass).getConstructor().newInstance());
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
}
As an additional note, registering interface implementation via configuration files sounds like you should have a look at the ServiceLoader API and the underlying mechanisms. See also the Creating Extensible Applications chapter of the Java tutorial.
Why don't you try something like this, instead of declaring the types individually for functions, make the class generic and class handles this T types of Class instances.
class ImplMap<T> {
// Values are already related here
Map<Class<T>, Class<? extends T>> map;
// Already compiler aware of the type.
void put(Class<T> keyClass, Class<? extends T> valueClass) {
map.put(keyClass, valueClass);
}
// Compiler already aware of the type just like with 'put'.
Class<? extends T> get(Class<T> keyClass) {
return map.get(keyClass);
}
}
This doesn't involve unchecked cast since the type relationship already defined with the Map declaration and no need to SuppressWarning (Compiler doesn't warn).
Although compiler would warn about unchecked call when invoke the put and get function if you don't define type on ImplMap object creation as it not takes a type at all and if you define a type, you can put that type of keys only into that map which duplicates.
I'd like to create the following:
//infer the type from parameter but restrict it to one of
// Proxy's subtype. return a list of this sub type
public static List<T> process(<T extends Proxy> proxy)
{
return new ArrayList<T>(); //just for example
}
Usage:
List<ConcreteTypeOfProxy> list = process(new ConcreteTypeOfProxy());
The above example has compilation issues. I think this should logically be available in java, just not sure what the syntax is
//Any array that extends T
public static <T extends Proxy> List<T> process(T proxy)
{
return new ArrayList<T>(); //just for example
}
//Returns array that has T type of parameter
public static <T> List<T> process(T proxy)
{
return new ArrayList<T>(); //just for example
}
//Returns a map of generic type which you define in the method
public static <T, E extends Proxy> Map<T, E> process(T key, E value)
{
Map<T, E> map = new HashMap<T, E>();
map.put(key, value);
return map;
}
You don't need any method, and consequently you don't need any parameters, to do this:
List<ConcreteTypeOfProxy> list = new ArrayList<>();
Remember: there is no difference between ArrayList<ConcreteTypeOfProxy> and ArrayList<AnyOtherType>: it's just an ArrayList.
The type parameter is merely an instruction to the compiler to check the type of what is added - at compile time only - and to automatically cast values obtained from the list.
Just like java.util.Optional<T> in Java 8 is (somewhat) equivalent to Scala's Option[T] type, is there an equivalent to Scala's Either[L, R]?
There is no Either type is Java 8, so you need to create one yourself or use some third-party library.
You may build such a feature using the new Optional type (but read to the end of this answer):
final class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(Optional.of(value), Optional.empty());
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left=l;
right=r;
}
public <T> T map(
Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc)
{
return left.<T>map(lFunc).orElseGet(()->right.map(rFunc).get());
}
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc)
{
return new Either<>(left.map(lFunc),right);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> rFunc)
{
return new Either<>(left, right.map(rFunc));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc)
{
left.ifPresent(lFunc);
right.ifPresent(rFunc);
}
}
Example use case:
new Random().ints(20, 0, 2).mapToObj(i -> (Either<String,Integer>)(i==0?
Either.left("left value (String)"):
Either.right(42)))
.forEach(either->either.apply(
left ->{ System.out.println("received left value: "+left.substring(11));},
right->{ System.out.println("received right value: 0x"+Integer.toHexString(right));}
));
In retrospective, the Optional based solution is more like an academic example, but not a recommended approach. One problem is the treatment of null as “empty” which contradicts the meaning of “either”.
The following code shows an Either that considers null a possible value, so it’s strictly “either”, left or right, even if the value is null:
abstract class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<L,R>() {
#Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return lFunc.apply(value);
}
};
}
public static <L,R> Either<L,R> right(R value) {
return new Either<L,R>() {
#Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return rFunc.apply(value);
}
};
}
private Either() {}
public abstract <T> T map(
Function<? super L, ? extends T> lFunc, Function<? super R, ? extends T> rFunc);
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc) {
return this.<Either<T,R>>map(t -> left(lFunc.apply(t)), t -> (Either<T,R>)this);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> lFunc) {
return this.<Either<L,T>>map(t -> (Either<L,T>)this, t -> right(lFunc.apply(t)));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc) {
map(consume(lFunc), consume(rFunc));
}
private <T> Function<T,Void> consume(Consumer<T> c) {
return t -> { c.accept(t); return null; };
}
}
It’s easy to change that to a strict rejection of null by simply inserting an Objects.requireNonNull(value) at the beginning of both factory methods. Likewise, adding support for an empty either would be imaginable.
At the time of writing, vavr (formerly javaslang) is probably the most popular functional Java 8 library. It is pretty similar to lambda-companion's Either in my other answer.
Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();
There is no Either in the Java Standard Library. However there is an implementation of Either in FunctionalJava, along with many other nice classes.
cyclops-react has a 'right' biased either implementation called Xor.
Xor.primary("hello")
.map(s->s+" world")
//Primary["hello world"]
Xor.secondary("hello")
.map(s->s+" world")
//Secondary["hello"]
Xor.secondary("hello")
.swap()
.map(s->s+" world")
//Primary["hello world"]
Xor.accumulateSecondary(ListX.of(Xor.secondary("failed1"),
Xor.secondary("failed2"),
Xor.primary("success")),
Semigroups.stringConcat)
//failed1failed2
There is also a related type Ior which can act as an either or a tuple2.
disclosure I am the author of cyclops-react.
No, there is none.
Java language developers explicitly state that types like Option<T> are intended to be used only as temporary values (e.g. in stream operations results), so while they are the same thing as in other languages, they are not supposed to be used as they are used in other languages. So it is not surprising that there is no such thing as Either because it does not arise naturally (e.g. from stream operations) like Optional does.
There is a stand-alone implementation of Either in a small library, "ambivalence": http://github.com/poetix/ambivalence
You can get it from Maven central:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
lambda-companion has an Either type (and a few other functional types e.g. Try)
<dependency>
<groupId>no.finn.lambda</groupId>
<artifactId>lambda-companion</artifactId>
<version>0.25</version>
</dependency>
Using it is easy:
final String myValue = Either.right("example").fold(failure -> handleFailure(failure), Function.identity())
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.