marsouf
marsouf

Reputation: 1147

java 8 predicate type mismatch, this code seems logical to me

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

Answers (2)

Anton Balaniuc
Anton Balaniuc

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

Misha
Misha

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

Related Questions