【问题标题】:Force Stream::filter method to fail compile time when Predicate<? super Object> is passed rather than Predicate<? super T>当 Predicate<? 时强制 Stream::filter 方法编译失败传递了 super Object> 而不是 Predicate<?超级T>
【发布时间】:2020-10-26 11:40:30
【问题描述】:

我正在使用流 api 使用的预定义身份过滤器。不幸的是,我无法正确返回符合 stream api documentation 的通用谓词。

根据这里的反编译器是Stream::filter的定义:

public interface Stream<T> extends BaseStream<T, Stream<T>> {

    Stream<T> filter(Predicate<? super T> var1);

任何支持 Streams 的 Java 版本 (8~15) 我都面临这个问题。这个问题与我的实现无关。这段代码实际上足以重现它:

        Collection<String> result = Stream.of("A", "B", "C")
                                          .filter(new Object()::equals)
                                          .filter(Integer.valueOf(-1)::equals)
                                          .collect(Collectors.toSet());

在这里,应用了两个谓词,它们都不符合&lt;? super String&gt;...

根据this answer,这种行为似乎很奇怪......

我应该如何防止我的库的用户通过随机对象相等检查等过滤ServerState

理想情况下,我希望始终返回正确的谓词 super T> 不幸的是,没有任何编译时错误支持...

在这种情况下,使用 linter 不是解决方案。

尽管我知道下界通配符是如何工作的,但我一直缺少的是 Predicate&lt;? super Integer&gt; 可以成功转换为 Predicate&lt;? super String&gt;

地点:

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());

导致[] 空结果集。

这是我目前所拥有的,但对其中任何一个都不满意:

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);
        }
    }
}

在此处发布示例之前不存在名称类型为 is_* 的方法,因此将被删除...

编辑

尽管我知道下界通配符是如何工作的,但我一直缺少的是 Predicate&lt;? super Integer&gt; 可以成功转换为 Predicate&lt;? super String&gt;

地点:

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());

导致[] 空结果集。

【问题讨论】:

  • 阅读 PECS 以了解泛型类型参数和上限/下限

标签: java java-stream


【解决方案1】:

这里,两个谓词都不是 兼容

这不是真的:这 2 个谓词确实使用了一个 Object,它是 String 的父级。

&lt;? super String&gt; 不得与&lt;? extends String&gt; 混淆。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多