I have a common Transformer that simply filters a list using a given Predicate:
public class ListFilter<T> implements Observable.Transformer<List<T>, List<T>> {
private final Predicate<T> predicate;
private ListFilter(Predicate<T> predicate) {
this.predicate = predicate;
}
public static <T> Observable.Transformer<List<T>, List<T>> create(Predicate<T> predicate) {
return new ListFilter<>(predicate);
}
#Override
public Observable<List<T>> call(Observable<List<T>> listObservable) {
return listObservable
.flatMap(list -> Observable.from(list)
.filter(predicate::test)
.toList());
}
}
Now I can filter a list of items with a minimum boilerplate, like this:
repository.observeItems() // returns Observable<List<SomeItem>>
.compose(ListFilter.create(item -> /* some filter logic */)
But there's something I can't explain:
List<? extends Dummy> list = SomeDummyFactory.create();
BehaviorSubject<List<? extends Dummy>> subject = BehaviorSubject.create(list);
// #1 -> ok
BehaviorSubject.create(list)
.compose(ListFilter.create(item -> /* `item` is `Dummy` */)
...
// #2 -> error
subject
.compose(ListFilter.create(item -> /* `item` is `Object` */))
...
// #3 -> ok
subject
.map(any -> any) // do nothing
.compose(ListFilter.create(item -> /* `item` is `Dummy` */))
...
The only difference I can see between #2 and #3 is the expected wildcards of a Transformer<T, R>:
_#2: Transformer<? super List<? extends Dummy>, ? extends R>
_#3: Transformer<? super List<capture of ? extends Dummy>, ? extends List<capture of ? extends Dummy>
So there're a few questions:
Why Object is the type of an item in the 2nd case (and not Dummy)?
Why can't Java infer the return type of a Transformer in the 2nd case?
How does map operator help with it?
Why does the 1st case work fine?
It is because compiler can't re-capture wildcard type.
In your first case, you can try to add explicit generic. Both <Dummy> and <Object> will lead error. The fact geneirc type is (captrue#1 ?) extends Dummy which is infered by the create's generic return value.
In your second case, your subject generic type is List<? extends Dummy>. The compose must accept Transformer<? super List<? extends Dummy>,? extends R>>, so the create generic must be ? extends Dummy(same as case 1). But in current compile context (current statement), the wildcard type is not captured. Compiler can't infer the generic type, it simply use Object, so error happens.
In your third case, the map capture the wildcard type back. You can try any method with a generic Observable<R> return type, all of them will work. Such as .flatMap(d -> Observable.just(d)).
But note, your case 3 is just a workaround. The recommanded solution is let your ListFilter's generic more flexible.
You should define it as ObservableTransformer<List<? extends T>, List<? extends T>>
class ListFilter<T> implements ObservableTransformer<List<? extends T>, List<? extends T>> {
public static <T> ListFilter<T> create(Predicate<T> predicate) {
return new ListFilter<>(predicate);
}
private final Predicate<T> predicate;
private ListFilter(Predicate<T> predicate) {
this.predicate = predicate;
}
#Override
public ObservableSource<List<? extends T>> apply(Observable<List<? extends T>> upstream) {
return upstream
.flatMapSingle(list -> Observable.fromIterable(list)
.filter(predicate::test)
.toList());
}
}
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>.
The following classes and methods:
class A<T extends B> { }
class B {}
Stream<A<? extends B>> find() {
return findAll() // Stream<Optional<A<? extends B>>>
.filter(Optional::isPresent) // Stream<Optional<A<? extends B>>>
.map(Optional::get) // Stream<A<capture of ? extends B>>
.filter(a -> false); // Stream<A<capture of ? extends B>>
}
Stream<Optional<A<? extends B>>> findAll() {
return Stream.empty();
}
Compile fine with javac, but lead to type errors in IDEA:
The errors disappear when I either
Remove the filter(Optional::isPresent()).map(Optional::get) pair
Remove the ultimate filter call
I can't make any sense of that. Is it an IDEA bug?
Edit:
Some new insights thanks to LuCio :
While my version of javac (10.0.2) does not complain, other javac versions and IDEs do, so it's not an IDEA bug
Splitting the expression in two and giving the intermediate value an explicit type helps:
Stream<A<? extends B>> aStream = findAll()
.filter(Optional::isPresent)
.map(Optional::get);
return aStream
.filter(a -> false);
(note that the type IDEA infers for aStream is Stream<? extends A<? extends B>>, although it just accepts the assignment to this type)
So the question becomes: Why is the intermediate type the way it is, and why is it apparently OK to just ignore it by assigning to another type?
It's because Stream.map has the following signature:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
In this case, R is A<? extends B>. Hence, the return value of the function is implicitly
? extends A<? extends B>
At which point, I believe this question is to an extent answered by
Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?
This can be made to compile nicely by either changing the return type:
<T extends B> Stream<? extends A<? extends B>> find() {
return findAll() // Stream<Optional<A<? extends B>>>
.map(Optional::get) // Stream<A<capture of ? extends B>>
.filter(a -> false); // Stream<A<capture of ? extends B>>
}
or explicitly casting the function to return A<? extends B>:
<T extends B> Stream<A<? extends B>> find() {
return findAll()
.map((Function<Optional<A<? extends B>>, A<? extends B>>) Optional::get)
.filter(a -> false);
}
To clarify, a Stream<C>, where C extends A<B>, is not itself a Stream<A<? extends B>>.
I have the following code which compiles successfully:
import java.lang.String;
import java.util.List;
import java.util.Arrays;
interface Supplier<R> {
Foo<R> get();
}
interface Foo<R> {
public R getBar();
public void init();
}
public class Main {
static private <V> void doSomething(final Supplier<? extends List<? extends V>> supplier) {
// do something
}
static public void main(String[] args) {
doSomething(new Supplier<List<Object>>(){
#Override
public Foo<List<Object>> get() {
return new Foo<List<Object>>(){
#Override
public List<Object> getBar() {
return null;
}
#Override
public void init() {
// initialisation
}
};
}
});
}
}
However, if I convert the Supplier to the following lambda expression the code does not compile anymore:
doSomething(() -> new Foo<List<Object>>(){
#Override
public List<Object> getBar() {
return null;
}
});
The compiler error is:
Main.java:22: error: method doSomething in class Main cannot be applied to given types;
doSomething(() -> new Foo<List<Object>>(){
^
required: Supplier<? extends List<? extends V>>
found: ()->new Fo[...]; } }
reason: cannot infer type-variable(s) V
(argument mismatch; bad return type in lambda expression
<anonymous Foo<List<Object>>> cannot be converted to Foo<List<? extends V>>)
where V is a type-variable:
V extends Object declared in method <V>doSomething(Supplier<? extends List<? extends V>>)
If I change the declaration of the supplier to Supplier<? extends List<V>>, both variants compile successfully.
I compile the code with a Java 8 compiler.
Why does the code with the lambda not compile, although it is equivalent to the non-lambda version?
Is this a known/intended limitation of Java or is it a bug?
If I use:
doSomething(() -> () -> null);
It just works fine and all types are correctly inferred by the compiler.
If I try yo do:
doSomething(() -> () -> 1);
Compilation fails, and this is correct, because the doSomething method expects a Supplier<? extends List<? extends V>> argument and () -> () -> 1 isn't.
And if I do:
doSomething(() -> () -> Arrays.asList(1, 2, 3));
It works as expected.
So there's no need to cast anything here, just using lambdas and letting the compiler do its work is fine.
EDIT:
And if I do this:
doSomething(() -> new Foo<List<? extends Object>>() {
#Override
public List<? extends Object> getBar() {
return null;
}
});
It compiles without error.
So bottom line, the problem is that the compiler thinks that List<Object> is not the same as a List<? extends Object>, and when you're using lambda expressions, it just complains about it (wrongly). It doesn't complain with anonymous inner classes, though, so it all indicates this is a bug.
The issue is caused by using ? extends V with List in doSomething method definition, and but when invoke method, you are using new Foo<List<Object>> directly.
In there, List<? extends Object> is not equal to List<Object>, Since ? extends Object is covariance with type Object, for example, you can not put Object type element into List<? extends Object>, because compiler can't infer what's the type should be ? extends Object.
So for your example, you can try to fix it by directly using new Foo<List<? extends Object>>(), maybe like:
doSomething(() -> new Foo<List<? extends Object>>() {
#Override
public List<Object> getBar() {
return null;
}
});
And for why use the anonymous class can work in here, try to decompile the anonymous class,
class Main$1$1 implements Foo<java.util.List<java.lang.Object>>
...
final class Main$1 implements SupplierT<java.util.List<java.lang.Object>> {
...
as you can see, it's overriding the ? extends V as Object type.
but for lambda, it will not generate the corresponding anonymous class, for example:
class Main$1 implements SupplierT<java.util.List<java.lang.Object>>
the above anonymous class will not generate, and lambda will use invokedynamic instruction directly call, as:
0: invokedynamic #5, 0 // InvokeDynamic #0:get:()LSupplierT;
So it's still try to infer ? extends V, it will cause compile fails.
Reference:
https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html
or this example:
Is List a subclass of List? Why are Java generics not implicitly polymorphic?
In this particular situation an explicit cast can help:
doSomething((Supplier<List<Object>>) () -> new Foo<List<Object>>() {
^
#Override
public List<Object> getBar() {
return null;
}
});
Or, even simpler:
doSomething((Supplier<List<Object>>) () -> (Foo<List<Object>>) () -> null);
doSomething(() -> () -> null);
Sometimes, Java compiler can not infer the type that matches your intent, therefore you can specify it explicitly. One more example without casting (take a look at the left-hand side of a declaration):
Supplier<List<Object>> supplier = () -> new Foo<List<Object>>() {
#Override
public List<Object> getBar() {
return null;
}
};
doSomething(supplier);
At the same time, when you write:
static <V> void doSomething(final Supplier<? extends List<? extends V>> supplier) {
}
doSomething(() -> new Foo<List<Object>>() {
#Override
public List<Object> getBar() {
return null;
}
});
the expected return type in the lambda expression is:
Foo<List<? extends V>>
which is not the same as the actual:
Foo<List<Object>>
The compiler tells you about that in the output:
reason: cannot infer type-variable(s) V
argument mismatch; bad return type in lambda expression
<anonymous Foo<List<Object>>> cannot be converted to Foo<List<? extends V>>
How to get all elements of a list by instance?
I have a list that can have any class implementation of an interface Foo:
interface Foo;
class Bar implements Foo;
I want to use the java8 stream api to provide a utility method for extracting all elements of a specific class type:
public static <T extends Foo> List<T> getFromList(List<Foo> list, Class<T> type) {
return (List<T>) list.stream().filter(entry -> type.isInstance(entry)).collect(Collectors.toList());
}
using:
List<Foo> list;
List<Bar> bars = Util.getFromList(list, Bar.class);
Result: It works, but I have to add #SuppressWarnings due to the unchecked cast of (List<T>). How can I avoid this?
Introducing another type parameter that extends S is correct, however, in order to have the result as List<S>, but not as List<T>, you have to .map() the entries that pass the type::isInstance predicate to S.
public static <T extends Foo, S extends T> List<S> getFromList(List<T> list, Class<S> type) {
return list.stream()
.filter(type::isInstance)
.map(type::cast)
.collect(Collectors.toList());
}
As suggested by #Eran, this can be even simplified to work with just one type parameter:
public static <T extends Foo> List<T> getFromList(List<Foo> list, Class<T> type) {
return list.stream()
.filter(type::isInstance)
.map(type::cast)
.collect(Collectors.toList());
}
This seems to work without warnings :
public static <T extends Foo> List<T> getFromList(List<Foo> list, Class<T> type) {
return list.stream()
.filter(entry -> type.isInstance(entry))
.map(entry->type.cast(entry))
.collect(Collectors.toList());
}
Tested with Number replacing Foo and Integer replacing Bar :
public static <T extends Number> List<T> getFromList(List<Number> list, Class<T> type) {
return list.stream().filter(entry -> type.isInstance(entry)).map(entry->type.cast(entry)).collect(Collectors.toList());
}
public static void main(String[] args)
{
List<Number> list = new ArrayList<>();
list.add(5);
list.add(3.4);
list.add(7);
List<Integer> bars = getFromList(list, Integer.class);
System.out.println(bars);
}
Output:
[5, 7]
As list and type are not of the same type but rather in a inheritance hierarchy relation, you will likely to add another type argument similar to the following:
public static <T extends Foo, S extends T> List<T> getFromList(List<T> list, Class<S> type) {
return list.stream().filter(type::isInstance).collect(Collectors.toList());
}
I have the following BeanValidation code that works fine, and permits to validate that a bean annotated with:
#EnumValue(enumClass = MyTestEnum.class)
private String field;
public enum MyTestEnum {
VAL1, VAL2;
}
Will be validated only if the field value is "VAL1" or "VAL2".
public class EnumNameValidator implements ConstraintValidator<EnumValue, String> {
private Set<String> AVAILABLE_ENUM_NAMES;
#Override
public void initialize(EnumValue enumValue) {
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = Sets.newHashSet(enumSelected.getEnumConstants());
AVAILABLE_ENUM_NAMES = FluentIterable
.from(enumInstances)
.transform(PrimitiveGuavaFunctions.ENUM_TO_NAME)
.toImmutableSet();
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ( value == null ) {
return true;
} else {
return AVAILABLE_ENUM_NAMES.contains(value);
}
}
}
What I don't understand is why my first attempt failed. Using instead of the enumSelected.getEnumConstants() above the following code:
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
Intellij 12 doesn't highlight any error, but the compiler says:
java: method allOf in class java.util.EnumSet<E> cannot be applied to given types;
required: java.lang.Class<E>
found: java.lang.Class<capture#1 of ? extends java.lang.Enum<?>>
reason: inferred type does not conform to declared bound(s)
inferred: capture#1 of ? extends java.lang.Enum<?>
bound(s): java.lang.Enum<capture#1 of ? extends java.lang.Enum<?>>
I don't understand the problem, and I also have that code which works fine:
private static <T extends Enum<T> & EnumAlternativeName> T safeGetByAlternativeName(Class<T> enumClass, String alternativeName) {
for ( T t : EnumSet.allOf(enumClass) ) {
if ( t.getAlternativeName().equals(alternativeName) ) {
return t;
}
}
return null;
}
My guess is that in ? extends Enum<?> the two ? could be different whereas allOf expects a T extends Enum<T> where both T are the same.
For example, consider the following code:
static enum MyEnum {}
static class EnumValue<T extends Enum<T>> {
Class<T> enumClass;
EnumValue(Class<T> enumClass) {
this.enumClass = enumClass;
}
Class<T> enumClass() { return enumClass; }
}
These lines will compile:
EnumValue<?> enumValue = new EnumValue(MyEnum.class); // raw constructor
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumValue.enumClass());
because we know that the two T in enumValue.enumClass() are the same but this won't:
EnumValue enumValue = new EnumValue(MyEnum.class);
Class<? extends Enum<?>> enumSelected = enumValue.enumClass();
Set<? extends Enum<?>> enumInstances = EnumSet.allOf(enumSelected);
because you have lost information by using a Class<? extends Enum<?>> as an intermediate step.
My explanation on #assylias's solution:
What we want to express about the type of the class is that it's a
Class<E>, for some E, that E <: Enum<E>
but Java does not allow us to introduce a type variable E in a method body.
Usually, we can exploit wildcard and wildcard capture to introduce a hidden type variable
class G<T extends b(T)> { ... } // b(T) is a type expression that may contain T
G<? extends A> --capture--> G<T>, for some T, that T <: A & b(T)
But this won't work in our case, since T in Class<T> does not have a bound that makes it work.
So we need to introduce a new type with the desired bound
class EnumClass<E extends Enum<E>> // called EnumValue in assylias's solution
EnumClass(Class<E> enumClass)
Class<E> enumClass()
EnumClass<?> --capture--> EnumClass<E>, for some E, that E <: Enum<E>
We then call EnumClass<E>.enumClass() to yield a
Class<E>, for some E, that E <: Enum<E>
which is the goal we've been trying to achieve.
But how can we call the constructor of EnumClass? The origin of the problem is that we don't have a proper type for enumClass, yet the constructor of EnumClass wants a properly typed enumClass.
Class<not-proper> enumClass = ...;
new EnumClass<...>(enumClass); // wont work
Fortunately(?) the raw type helps here which disables generics type checking
EnumClass raw = new EnumClass(enumClass); // no generics
EnumClass<?> wild = raw;
So the minimum gymnastics we need to perform to cast the class to the desired type is
((EnumClass<?>)new EnumClass(enumClass)).enumClass()