As discussed in Bounding generics with 'super' keyword the Java type system is broken/incomplete when it comes to lower bounds on method generics. Since Optional is now part of the JDK, I'm starting to use it more and the problems that Guava encountered with their Optional are starting to become a pain for me. I came up with a decent work around, but I'm not sure its safe. First, let me setup the example:
public class A {}
public class B extends A {}
I would like to be able to declare a method like:
public class Cache {
private final Map<String, B> cache;
public <T super B> Optional<T> find(String s) {
return Optional<T>.ofNullable(cache.get(s));
}
}
So that both of the following work:
A a = cache.find("A").orElse(new A())
B b = cache.find("B").orElse(new B())
As a workaround, I have a static utility method as follows:
public static <S, T extends S> Optional<S> convertOptional(Optional<T> optional) {
return (Optional<S>)optional;
}
So my final question, is this as type-safe as the 'ideal' code above?
A a = OptionalUtil.<A,B>convertOptional(cache.find("A")).orElse(new A());
You're effectively trying to view the Optional<B> returned as an Optional<A> without changing the return type (since you can't use the super). I would just map the identity function.
A a = cache.find("A").map(Function.<A> identity()).orElse(new A());
// or shorter
A a = cache.find("A").<A> map(x -> x).orElse(new A());
I don't see anything wrong with your approach though.
Yes, your code is type safe because you are casting Optional<T> to Optional<S>, and T is always an S. You can indicate this to the compiler by using the #SuppressWarnings("unchecked") annotation on your convertOptional utility method.
As well as the other excellent answer, you could do it this way. Note the lack of generics compared to your first version.
package com.company;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
public class Cache {
private static final Function<A,A> CAST_TO_A = Function.<A>identity();
private final Map<String, B> cache = new HashMap<>();
public Optional<B> find(String s) {
return Optional.ofNullable(cache.get(s));
}
public static void main(String[] args) {
Cache cache = new Cache();
Optional<B> potentialA = cache.find("A");
A a = potentialA.isPresent() ? potentialA.get() : new A();
A anotherWay = cache.find("A").map(CAST_TO_A).orElse(new A());
B b = cache.find("B").orElse(new B());
}
public static class A {}
public static class B extends A {}
}
In practice, I think it is type-safe, because the Optional class is immutable and T is subtype of S.
Beware though that T is subtype of S does NOT mean that Optional<T> is subtype of Optional<S>, so theoretically that cast is not correct. And in some cases, it is not safe to do such kind of casts and it can be problematic at run-time (as it happens with List).
So my suggestion is to avoid casts whenever we can, and I would rather define a method like the getOrElse. Also, for the sake of completeness, the generic types in your method convertOptional could be simplified as below.
class OptionalUtil {
public static <S> S getOrElse(Optional<? extends S> optional, Supplier<? extends S> other) {
return optional.map(Function.<S>identity()).orElseGet(other);
}
public static <S> Optional<S> convertOptional(Optional<? extends S> optional) {
return (Optional<S>)optional;
}
}
And they could be use like that:
A a1 = OptionalUtil.getOrElse(cache.find("A"), A::new);
A a2 = OptionalUtil.<A>convertOptional(cache.find("A")).orElseGet(A::new);
[EDIT] I replaced the method orElse by orElseGet, because with the former a new A object will be created even if the Optional is present.
I would like to implement the following method, but I'm uncertain how to do this in Java generics.
This is what I would like to have:
public <C extends Collection> C<DomainDTO> transform(C<DomainModel> arg);
This is what compiles, but doesn't ensure A and B are of the same class that extends Collection:
public <A extends Collection<DomainDTO>, B extends Collection<DomainModel>> A transform(B arg);
Thanks for any ideas, or just confirmation that it's impossible.
EDIT:
I'll try to word this better, since it seems people confuse what I'm looking for. The use case here is (should be) simple. I need a method to populate a Collection of DTOs from a Collection of models. Right now I have many methods for different Collections, but I would prefer to have one generic method that takes any Collection as the parameter, and returns the DTOs in a Collection of the same class.
Specify the type of the collection parameter, not the collection itself:
public <T> Collection<T> transform(Collection<T> arg);
If the question is asking for both the element type and the collection type to be the same:
public <T, C extends Collection<T>> C transform(C arg);
EDIT: The question originally was ambiguous, to say the least. My proposed solution is not applicable to the edited question. However, the recommendation I made is still valid:
I wonder how you would like to implement this without using newInstance etc. You have to create a new instance of an unknown type...
You might alternatively consider a signature [...] where the caller can pass the target collection manually, and type safety is still maintained
EDIT: Updated code for the updated question:
The most generic form that I could imagine for this is sketched below.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SomeCollectionTest
{
static interface Converter<S, T>
{
T convert(S s);
}
static class Parser implements Converter<String, Integer>
{
#Override
public Integer convert(String s)
{
return Integer.parseInt(s);
}
}
public static void main(String[] args)
{
Collection<String> input = Arrays.asList("0","1","2","3");
List<String> listIn = new ArrayList<String>(input);
Set<String> setIn = new HashSet<String>(input);
Parser p = new Parser();
List<Integer> listOutA = convert(listIn, new ArrayList<Integer>(), p);
List<Integer> listOutB = convert(setIn, new ArrayList<Integer>(), p);
//List<Integer> noListOut = convert(listIn, new HashSet<Integer>(), p);
Set<Integer> setOutA = convert(setIn, new HashSet<Integer>(), p);
Set<Integer> setOutB = convert(setIn, new HashSet<Integer>(), p);
//Set<Integer> noSetOut = convert(listIn, new ArrayList<Integer>(), p);
System.out.println(listOutA);
System.out.println(setOutA);
}
private static <S, T, C extends Collection<? super T>> C convert(
Iterable<? extends S> input, C output, Converter<S, T> converter)
{
for (S s : input)
{
output.add(converter.convert(s));
}
return output;
}
}
And by the way: I'd even consider it as being advantageous to have the possibility to convert, for example, a Collection<DomainDTO> into a List<DomainModel> - particularly when you don't know the exact type of the first collection. Otherwise, you'd have to do this in two steps:
Collection<DTO> collectionOfDto = read();
Collection<DomainModel> dm = convert(dto); // Only receive a collection here...
// Sigh, I need a list. Maybe it already IS a list, but
// I don't know it. So I have to do this:
List<DomainModel> list = new ArrayList<DomainModel>(dm);
How does one get a parameterized Class object to be used as a method argument?
class A<T>
{
public A(Class<T> c)
{
}
void main()
{
A<String> a1 = new A<String>(String.class); // OK
A<List<String>> a2 = new A<List<String>>(List<String>.class); // error
A<List<String>> a3 = new A<List<String>>(Class<List<String>>); // error
}
}
Why do I want to do that, you may ask? I have a parameterized class whose type is another parameterized class, and whose constructor requires that other class type as an argument. I understand that runtime classes have no information on their type parameters, but that shouldn't prevent me from doing this at compile time. It seems that I should be able to specify a type such as List<String>.class. Is there another syntax to do this?
Here is my real usage case:
public class Bunch<B>
{
Class<B> type;
public Bunch(Class<B> type)
{
this.type = type;
}
public static class MyBunch<M> extends Bunch<List<M>>
{
Class<M> individualType;
// This constructor has redundant information.
public MyBunch(Class<M> individualType, Class<List<M>> listType)
{
super(listType);
this.individualType = individualType;
}
// I would prefer this constructor.
public MyBunch(Class<M> individualType)
{
super( /* What do I put here? */ );
this.individualType = individualType;
}
}
}
Is this possible?
How about just cast?
super((Class<List<M>>)List.class);
Class literals are not going to have the type parameters that you want.
Remember you will NOT get a List as a class in runtime, and the right approach would probably be using TypeToken as BalusC told you. Without TypeToken, you can't cast to List, but you can create something like this:
public static class MyBunch2<List_M extends List<M>, M> extends Bunch<List_M>
{
Class<M> individualType;
#SuppressWarnings("unchecked")
public MyBunch2(Class<M> individualType)
{
super((Class<List_M>) List.class);
this.individualType = individualType;
}
}
Since List_M extends List<M> this is not as typesafe as you may wish, but maybe is nice enough. Creating an instance will be as ugly as writing
MyBunch2<List<String>, String> a = new MyBunch2<List<String>, String>(String.class);
but you can improve it with a factory method
public static <M2> MyBunch2<List<M2>, M2> of(Class<M2> individualType){
return new MyBunch2<List<M2>, M2>(individualType);
}
and then write
MyBunch2<List<String>, String> b = MyBunch2.of(String.class);
If you are using eclipse, code assist will help you writing the ugly class MyBunch2, String>
Of course, in runtime, this.type will be java.util.List, not java.util.List
To get it right, go for TypeToken.
---Continuation---
You can even make another class
public static class MyBunch3<M> extends MyBunch2<List<M>, M>
{
public MyBunch3(Class<M> individualType) {
super(individualType);
}
}
And then create instances as
MyBunch3<String> c = new MyBunch3<String>(String.class);
There must be a way to do that in just one class...but I can't figure it out
I want to define a Functor class in Java. This works:
//a Function
public interface F<A,R> {
public R apply(A a);
}
public interface Functor<A> {
public <B> Functor<B> fmap(F<A,B> f);
}
However the return value of fmap should be not Functor, but the appropriate subclass. Usually this can be encoded with the CRTP, but here I seem to hit a wall because of the additional parameter A. E.g. the following and similar encodings don't work ("type parameter FInst is not within its bounds"):
public interface Functor<A, FInst extends Functor<A,FInst>> {
public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
[Clarification]
With "appropriate subclass" I mean the type of the class being called itself. E.g. Lists are functors, so I would like to write something like
public class ListFunctor<A> implements ??? {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
<B> ListFunctor<B> fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return new ListFunctor<B>(result);
}
}
I'm aware that I could write this even with the first definition I gave (because covariant return types are allowed), but I want that the return type "ListFunctor" is enforced by the type system (so that I can't return a FooFunctor instead), which means that the Functor interface needs to return the "self-type" (at least it is called so in other languages).
[Result]
So it seems what I want is impossible. Here is a related blog-post: http://blog.tmorris.net/higher-order-polymorphism-for-pseudo-java/
[Aftermath]
I stumbled over this age-old question of mine, and realized that this was the starting point of the amazing journey with my library highJ, containing much more than a simple Functor. I would have never imagine that people would use this crazy stuff for anything serious, but it happened, and that makes me very happy.
public interface Functor<A, FInst extends Functor<A,FInst>> {
public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
This code generates an error because when you define I, you define it to be a subclass of Functor<B,FInst>, but the FInst parameter must be a subclass of Functor<B,FInst> in this case, while it is defined above as being a subclass of Functor<A,FInst>. Since Functor<A,FInst> and Functor<B,FInst> aren't compatible, you get this error.
I haven't been able to solve this completely, but I could do at least a half of the job:
import java.util.ArrayList;
import java.util.List;
interface F<A,R> {
public R apply(A a);
}
interface Functor<A, FClass extends Functor<?, FClass>> {
public <B> FClass fmap(F<A,B> f);
}
public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
public <B> ListFunctor<B> fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return new ListFunctor<B>(result);
}
}
This works, and it properly limits the set of allowed return types to ListFunctor, but it doesn't limit it to subclasses of ListFunctor<B> only. You could declare it as returning ListFunctor<A> or any other ListFunctor, and it would still compile. But you can't declare it as returning a FooFunctor or any other Functor.
The main problem with solving the rest of the problem is that you can't limit FClass to subclasses of ListFunctor<B> only, as the B parameter is declared at the method level, not at the class level, so you can't write
public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {
because B doesn't mean anything at that point. I couldn't get it working with the second parameter to the fmap() either, but even if I could, it would just force you to specify the return type twice - once in the type parameter and once more as the return type itself.
Looking from a different angle, it seems Functor shouldn't be modeled as a "Wrapper" around the data, but actually more like a type-class, which works on the data. This shift of perspective allows to encode everything without a single cast, and absolutely type-safe (but still with a lot of boilerplate):
public interface Functor<A, B, FromInstance, ToInstance> {
public ToInstance fmap(FromInstance instance, F<A,B> f);
}
public class ListFunctor<A,B> implements Functor<A, B, List<A>, List<B>> {
#Override
public List<B> fmap(List<A> instance, F<A, B> f) {
List<B> result = new ArrayList<B>();
for(A a: instance) result.add(f.apply(a));
return result;
}
}
List<String> stringList = Arrays.asList("one","two","three");
ListFunctor<String,Integer> functor = new ListFunctor<String,Integer>();
List<Integer> intList = functor.fmap(stringList, stringLengthF);
System.out.println(intList);
//--> [3, 3, 5]
It seems I was too focused on packing both FromInstance and ToInstance in one type parameter (e.g. List in ListFunctor), which isn't strictly necessary. However, it's a heavy burden to have now not only A but also B as type parameter, which may make this approach practically unusable.
[Research]
I found a way to make this version at least a little bit useful: This functor can be used to lift a function. E.g. if you have F<String, Integer>, you can construct a F<Foo<String>, Foo<Integer>> from it when you have a FooFunctor defined as shown above:
public interface F<A,B> {
public B apply(A a);
public <FromInstance, ToInstance> F<FromInstance, ToInstance> lift(
Functor<A,B,FromInstance, ToInstance> functor);
}
public abstract class AbstractF<A,B> implements F<A,B> {
#Override
public abstract B apply(A a);
#Override
public <FromInstance, ToInstance> F<FromInstance, ToInstance> lift(
final Functor<A, B, FromInstance, ToInstance> functor) {
return new AbstractF<FromInstance, ToInstance>() {
#Override
public ToInstance apply(FromInstance fromInstance) {
return functor.fmap(fromInstance, AbstractF.this);
}
};
}
}
public interface Functor<A, B, FromInstance, ToInstance> {
public ToInstance fmap(FromInstance instance, F<A,B> f);
}
public class ListFunctor<A, B> implements Functor<A, B, List<A>, List<B>> {
#Override
public List<B> fmap(List<A> instance, F<A, B> f) {
List<B> result = new ArrayList<B>();
for (A a : instance) {
result.add(f.apply(a));
}
return result;
}
}
//Usage:
F<String, Integer> strLenF = new AbstractF<String, Integer>() {
public Integer apply(String a) {
return a.length();
}
};
//Whoa, magick!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
F<List<String>,List<Integer>> liftedF = strLenF.lift(new ListFunctor<String, Integer>());
List<String> stringList = Arrays.asList("one", "two", "three");
List<Integer> intList = liftedF.apply(stringList);
System.out.println(intList);
//--> [3, 3, 5]
I think it's still not very useful, but at least way cooler than the other attempts :-P
Building on the answer of Sergey, I think I came close to what I wanted. Seems like I can combine his idea with my failed attempt:
public interface Functor<A, Instance extends Functor<?, Instance>> {
public <B, I extends Functor<B,Instance>> I fmap(F<A,B> f);
}
public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
public <B, I extends Functor<B, ListFunctor<?>>> I fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return (I) new ListFunctor<B>(result);
}
}
List<String> list = java.util.Arrays.asList("one","two","three");
ListFunctor<String> fs = new ListFunctor<String>(list);
ListFunctor<Integer> fi = fs.<Integer,ListFunctor<Integer>>fmap(stringLengthF);
//--> [3,3,5]
The remaining problem is that I could write e.g. ListFunctor<StringBuilder> fi = fs.<Integer,ListFunctor<StringBuilder>> without complaints from the compiler. At least I can look for a way to hide the ugly guts behind a static method, and to enforce that relation behind the scenes...
Does anyone still use Java and ponder this problem? You might find this useful...
I've been pondering this for a looooong time. I believe I've made something satisfactory. What I would really like to is indeeed impossible in Java.
This is ideal:
interface Functor<T, CONCRETE<A> extends Functor<A, CONCRETE>> {
CONCRETE<U> fmap(Func<T, U>);
}
Unfortunately, this is make-believe syntax. This kind of thing is possible in C++ with template-template parameters, but not Java.
I was tempted to write this simple thing:
interface Functor<T> {
Functor<U> fmap(Func<T, U>);
}
This works in some cases, because an implementation can return a covariant return type (for example, List could return a List from this function), but it breaks down when you try passing around generic variables of type "F extends Functor", or a subclass of Functor, etc...
What I ended up doing was introduce a "dummy type variable", like so:
interface Functor<CONCRETE, T> {
Functor<CONCRETE, U> fmap(Func<T, U>);
}
The "concrete type" should be the type itself, or some dummy type that guarantees the uniqueness of its implementors. Here's an example implementation:
public final class Array<T> implements Functor<Array<?>, T> {
private final T[] _values;
#SafeVarargs
public Array(T... values) {
_values = values;
}
#SuppressWarnings("unchecked")
#Override
public <A, RESULT extends Functor<Array<?>, A>> RESULT fmap(Function<T, A> f) {
A[] result = (A[]) new Object[_values.length];
for (int i = 0; i < _values.length; ++i) {
result[i] = f.apply(_values[i]);
}
return (RESULT) new Array<A>(result);
}
}
The cast to (RESULT) is safe because there can only be one type that matches "Functor, T>", and that's "Array". The disadvantage of this, is that generic code may need to pass around this "CONCRETE" type in a bunch of places, and it makes your signatures unwieldy. For instance:
public class Test {
public static <CONCRETE, FInt extends Functor<CONCRETE, Integer>, FBool extends Functor<CONCRETE, Boolean>> FBool intToBool(FInt ints) {
return ints.fmap(x -> x > 5);
}
public static void main() {
Array<Integer> ints = new Array<>();
Array<Boolean> bools1 = ints.fmap(x -> x > 5); // this works because Array<> implements fmap covariantly
Array<Boolean> bools2 = intToBool(ints); // but this also works thanks to our dummy CONCRETE type
}
}
I think you want to do something that makes no sense (type wise).
interface Getter<Type> {
Type get();
}
If your application wants a getter that returns Integers, don't give it one that returns Objects.
If you don't know if it will return Objects or Integers you are trying to do something the wrong way.
If YOU KNOW it will return Integers, then wrap the getter so that it casts to integers.
Hope this is what you are looking for .
EDIT:
Explanation of why (I think) this can not be done.
Objects have there types set when you use new.
Take each type and replace it with a letter.
Take any number of another objects and do the same.
What letter do you want your function to return?
If the answer is that you want a mix, well then its too late. Types are decided at new, and you are already past new.