减少Java 8中的UnaryOperators列表 [英] Reducing a list of UnaryOperators in Java 8

查看:104
本文介绍了减少Java 8中的UnaryOperators列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java 8中减少一个UnaryOperator列表直到它们代表一个我可以调用apply的UnaryOperator的首选方法是什么? 例如,我有以下

What is the preferred way of reducing a list of UnaryOperators in Java 8 till they represent one UnaryOperator that I can call apply on? For example I have the following

interface MyFilter extends UnaryOperator<MyObject>{};

public MyObject filterIt(List<MyFilter> filters,MyObject obj){
Optional<MyFilter> mf = filters
                           .stream()
                           .reduce( (f1,f2)->(MyFilter)f1.andThen(f2));

return mf.map(f->f.apply(obj)).orElse(obj);

}

但是此代码在(MyFilter)f1.andThen(f2)处抛出ClassCastException. 我真的很想要这段代码的效果:

But this code throws a ClassCastException at (MyFilter)f1.andThen(f2). I really want the effect of this code in the end:

MyObject o = obj;
for(MyFilter f:filters){
  o = f.apply(o);
}
return o;

但是我也很好奇我们如何使用composeandThen将一组函数简化为一个函数.

But I am also curious of how we can reduce a collection of functions to one function, using compose or andThen.

推荐答案

使用composeandThen的问题在于它们是内置在Function接口和类型中的-编译时和编译时运行时类型-它们返回的函数是Function而不是UnaryOperator或您定义的子接口.例如,假设我们有

The problem with using compose or andThen is that they're built into the Function interface and the type -- both compile-time and runtime types -- of the functions they return is Function and not UnaryOperator or a subinterface such as you've defined. For example, suppose we have

UnaryOperator<String> a = s -> s + "bar";
UnaryOperator<String> b = s -> s + s;

一个人可能以为我们可以写

One might think we could write

UnaryOperator<String> c = a.compose(b);

但这不起作用!相反,必须写

but this doesn't work! Instead, one has to write

Function<String, String> c = a.compose(b);

为此,UnaryOperator必须提供andThencompose的协变量替代. (可以说这是API中的错误.)您可以在子接口中执行相同的操作.或者,手动写出lambda很简单.例如,

For this to work, UnaryOperator would have to provide covariant overrides of andThen and compose. (Arguably this is a bug in the API.) You'd do the same in your subinterface. Or, it's simple enough to write out the lambdas by hand. For example,

interface MyOperator extends UnaryOperator<String> { }

public static void main(String[] args) {
    List<MyOperator> list =
        Arrays.asList(s -> s + "bar",
                      s -> "[" + s + "]",
                      s -> s + s);

    MyOperator composite =
        list.stream()
            .reduce(s -> s, (a, b) -> s -> b.apply(a.apply(s)));

    System.out.println(composite.apply("foo"));
}

这将打印出[foobar][foobar].请注意,为了避免不得不处理Optional,我使用了reduce的两个参数形式.

This prints out [foobar][foobar]. Note that I've used the two-arg form of reduce in order to avoid having to deal with Optional.

或者,如果您经常进行函数组合,则可以在自己的界面中重新实现所需的方法.不太难.这些基于java.util.Function中的实现,但是在本示例中我一直使用具体的String类型代替泛型.

Alternatively, if you're doing function composition a lot, you could reimplement the methods you need in your own interface. It's not too hard. These are based on the implementations in java.util.Function but with the concrete String type I've been using in this example substituted for the generics.

interface MyOperator extends UnaryOperator<String> {
    static MyOperator identity() {
        return s -> s;
    }

    default MyOperator andThen(MyOperator after) {
        Objects.requireNonNull(after);
        return s -> after.apply(this.apply(s));
    }

    default MyOperator compose(MyOperator before) {
        Objects.requireNonNull(before);
        return s -> this.apply(before.apply(s));
    }
}

这将按如下方式使用:

MyOperator composite =
    list.stream()
        .reduce(MyOperator.identity(), (a, b) -> a.andThen(b));

我想是否扩大接口以便编写andThen而不是嵌套的lambda只是一个问题.

Whether bulking up the interface in order to write andThen instead of a nested lambda is a matter of taste, I guess.

这篇关于减少Java 8中的UnaryOperators列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆