Reputation: 1147
This code seems logical to me, why the compiler is complaining about the predicate isBondAsset having the wrong type ?
I mean a "Predicate of any type that extends Asset" is a "Predicate of any type super of any type that extends Asset" or i'm wrong ?
private static class Asset
{
public enum AssetType
{
BOND,
STOCK;
}
private final AssetType type;
private final int value;
public Asset (AssetType type, int value)
{
this.type = type;
this.value = value;
}
public AssetType getType ()
{
return type;
}
public int getValue ()
{
return value;
}
}
private static class AssetUtils
{
public static int totalBondAssetValues (Collection <? extends Asset> assets)
{
Predicate<? extends Asset> isBondAsset = asset -> Asset.AssetType.BOND.equals(asset.getType());
return assets.stream().filter(isBondAsset).mapToInt(Asset::getValue).sum();
}
}
Upvotes: 2
Views: 976
Reputation: 11739
According to Stream#filter
/**
* Returns a stream consisting of the elements of this stream that match
* the given predicate.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to each element to determine if it
* should be included
* @return the new stream
*/
Stream<T> filter(Predicate<? super T> predicate);
so it should be
Predicate<? super Asset> isBondAsset
One of the main reasons for that, if I am not wrong, is possibility of using Predicates
already defined for <T>
super types:
List<String> stringList = Arrays.asList("1","22","3","44");
Predicate<Object> objectPredicate = o -> o.getClass().equals(String.class);
Predicate<CharSequence> charSequencePredicate = ch -> ch.length() == 2;
Predicate<String> stringPredicate = s -> s.contains("2");
stringList.stream().filter(objectPredicate).forEach(System.out::println);
stringList.stream().filter(charSequencePredicate).forEach(System.out::println);
stringList.stream().filter(stringPredicate).forEach(System.out::println);
Upvotes: 2
Reputation: 28133
Let's give names to the two type variables:
Collection<T> assets;
Predicate<R> isBondAsset;
Compiler knows that both T
and R
are subtypes of Asset
but that's all it has to go on. In order for Predicate<R>
to be applicable to Collection<T>
R
must be a supertype of T
, but you never declare it as such.
There is no reason for you to declare isBondAsset
with a wildcard. You should simply make it a Predicate<Asset>
. Then the code will compile because the compiler knows that Asset
is a supertype of any type that satisfies ? extends Asset
Upvotes: 2