List ::包含比较器

时间:2014-12-03 10:46:52

标签: java lambda java-8

有没有办法(方法,lambda或优雅构造)基于给定的比较器在列表中查找元素?

我写了一个像这样的方法:

private static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) {
    return list.stream()
            .anyMatch(listItem -> comparator.compare(listItem, item) == 0
            );
}

但我希望用更优雅的东西取代它。

我不想添加任何依赖项,因此没有Guava,“commons”等等。我真的在Java 8中寻找一种非常好的方法。

编辑:我认为更优雅的一些例子(这是使用代码):

// sadly, this method doesn't exist
// nor is there a static one in Collections
// but maybe you can think of another way?
if (list.containsSame(item, comparator)) {
    // ...
}

4 个答案:

答案 0 :(得分:8)

据我所知,没有直接解决此任务的内置功能。因此,既然你无法避免创建实用程序方法(如果你想减少代码重复),那么值得考虑哪种实用方法在其他场景中也很有用。

E.g。如果是我的项目,我知道几乎总有一些方法可以让部分功能应用飞来飞去,比如:

public static <T,U,R> Function<U,R> bind(BiFunction<T,U,R> f, T t) {
    return u -> f.apply(t, u);
}

利用这种现有方法,解决方案可能如下所示:

static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) {
  return list.stream().map(bind(comparator::compare, item))
                      .anyMatch(Predicate.isEqual(0));
}

但这不一定是最好的解决方案。

另一种方法可能是将Comparator转换为等式BiPredicate的方法和部分应用BiPredicate的实用方法:

public static <T> BiPredicate<T,T> match(Comparator<T> f) {
    return (a,b)->f.compare(a, b)==0;
}
public static <T,U> Predicate<U> bind(BiPredicate<T,U> f, T t) {
    return u -> f.test(t, u);
}

然后contains方法变得像

一样简单
static <T> boolean contains(List<T> list, T item, Comparator<? super T> comparator) {
  return list.stream().anyMatch(bind(match(comparator), item));
}

但如果实用程序方法也可以在项目的其他位置使用,那么这只是一种简化。另一方面,它们具有如下通用性质,类似的方法可能作为default方法添加到后续Java版本中的函数接口。在这种情况下,使用此类实用程序方法的代码已准备好迁移到较新版本。

答案 1 :(得分:1)

不确定这是否是你想要的,但有一种可能性就是创建你自己的扩展Stream的接口并提供你想要的方法(注意:UNTESTED):

public interface MyStream<R>
    extends Stream<R>
{
    // Yay! Static methods in interfaces!
    public static <E> MyStream<E> of(final Collection<E> collection)
    {
        return new MyStreamImpl<E>(collection);
    }

    // Yay! Default methods in interfaces!
    default boolean containsAny(R item, Comparator<? super R> comparator)
    {
        return anyMatch(e -> comparator.compare(item, e) == 0);
    }
}

public class MyStreamImpl<R>
    implements MyStream<R>
{
    private final Stream<R> stream;

    public MyStreamImpl(final Collection<R> collection)
    {
        this.stream = Objects.requireNonNull(collection.stream());
    }

    // delegate all other operations to stream
}

然后你可以使用:

MyStream.of(someList).containsAny(item, comparator);

(但很多代码的代码很多,真的)

答案 2 :(得分:1)

为什么要首先创建额外的功能?只需在每次流功能时调用。

如果你坚持,而不是Comparator,你可以使用BiPredicate

例如。

BiPredicate<Integer,Integer> greaterThan = (i,s) -> i > s;

并将您的包含功能更改为

private static <T> boolean containsp(List<T> list, T item, BiPredicate<? super T,? super T> biPredicate)     {
    return list.stream().filter(l-> biPredicate.test(l,item) ).findFirst().isPresent();
}

我不知道它是否更优雅,但似乎有效。

答案 3 :(得分:1)

您可以使用下一个方法from the commons-collections version 4+

  • @RequestMapping(value = "/login") public String login(@RequestParam(value = "error", defaultValue = "false") boolean error, Model model) { model.addAttribute("error", error); return "login"; } @RequestMapping("/session_timeout") public void sessionTimeout(HttpServletRequest request, HttpServletResponse response) throws IOException { System.out.println("session was timeout."); if (request.getHeader("x-requested-with") != null) { // handler for ajax response.getWriter().print("{\"sessionTimeout\": true}"); response.getWriter().close(); } else { response.sendRedirect("login"); } } - 检查对象是否包含在给定的iterable中。
  • IterableUtils.contains(Iterable<? extends E> iterable, E object, Equator<? super E> equator) - 如果谓词对于iterable的任何元素都为true,则为true。
相关问题