首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >减少Java8中的UnaryOperators列表

减少Java8中的UnaryOperators列表
EN

Stack Overflow用户
提问于 2014-06-03 03:07:53
回答 5查看 4.7K关注 0票数 9

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

代码语言:javascript
运行
复制
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)上抛出一个(MyFilter)f1.andThen(f2)。我真的想要这个代码的效果在最后:

代码语言:javascript
运行
复制
MyObject o = obj;
for(MyFilter f:filters){
  o = f.apply(o);
}
return o;

但我也很好奇如何使用composeandThen将一个函数集合简化为一个函数。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2014-06-03 03:57:39

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

代码语言:javascript
运行
复制
UnaryOperator<String> a = s -> s + "bar";
UnaryOperator<String> b = s -> s + s;

有人可能会认为我们可以写

代码语言:javascript
运行
复制
UnaryOperator<String> c = a.compose(b);

但这不管用!相反,一个人必须写

代码语言:javascript
运行
复制
Function<String, String> c = a.compose(b);

为此,UnaryOperator必须提供andThencompose的协变量重写。(可以说这是API中的一个bug。)你也会在你的子界面上做同样的事情。或者,用手把兰巴达写出来就够简单了。例如,

代码语言:javascript
运行
复制
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]。请注意,为了避免不得不处理reduce,我使用了双arg形式的Optional

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

代码语言:javascript
运行
复制
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));
    }
}

这将用于以下方面:

代码语言:javascript
运行
复制
MyOperator composite =
    list.stream()
        .reduce(MyOperator.identity(), (a, b) -> a.andThen(b));

我想,用扩展接口来编写andThen而不是嵌套的lambda是否是一个品味问题。

票数 17
EN

Stack Overflow用户

发布于 2014-06-03 08:48:17

MyFilterFunction继承andThen方法,因此返回的类型是Function,不能转换为MyFilter。但是,由于它具有所需的函数签名,所以可以使用lambda或方法引用创建MyFilter实例。

(f1,f2)->(MyFilter)f1.andThen(f2)改为(f1,f2)-> f1.andThen(f2)::apply

通过此更改,整个方法如下所示:

代码语言:javascript
运行
复制
public static MyObject filterIt(List<MyFilter> filters, MyObject obj) {
    Optional<MyFilter> mf =
      filters.stream().reduce( (f1,f2)-> f1.andThen(f2)::apply);
    return mf.map(f->f.apply(obj)).orElse(obj);
}

但你应该重新考虑你的设计。没有必要将结果函数作为MyFilter的实例,事实上,即使是输入也可以轻松接受,而不仅仅是接受List<MyFilter>

代码语言:javascript
运行
复制
// will accept List<MyFilter> as input
public static MyObject filterIt(
 List<? extends Function<MyObject,MyObject>> filters, MyObject obj) {
   List<Function<MyObject,MyObject>> l=Collections.unmodifiableList(filters);
   Optional<Function<MyObject,MyObject>> mf=l.stream().reduce(Function::andThen);
   return mf.orElse(Function.identity()).apply(obj);
}

或者,使用斯图亚特·马克斯的提示来摆脱Optional

代码语言:javascript
运行
复制
// will accept List<MyFilter> as input
public static MyObject filterIt(
  List<? extends Function<MyObject,MyObject>> filters,MyObject obj) {
    List<Function<MyObject,MyObject>> l=Collections.unmodifiableList(filters);
    return l.stream().reduce(Function.identity(), Function::andThen).apply(obj);
}

为了完整起见,您也可以将MyFilter链接到流上,而不是组合新函数:

代码语言:javascript
运行
复制
public static MyObject filterIt2(List<MyFilter> filters,MyObject obj) {
    Stream<MyObject> s=Stream.of(obj);
    for(MyFilter f: filters) s=s.map(f);
    return s.findAny().get();
}
票数 6
EN

Stack Overflow用户

发布于 2018-06-27 14:11:47

通过对函数接口的抽象方法使用方法引用语法,可以将一个函数接口转换为另一个函数接口。

代码语言:javascript
运行
复制
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

public class Example {
    public static void main(String[] args) {
        Stream<UnaryOperator<String>> stringMappers = Stream.of(
                s -> s + "bar",
                s -> "[" + s + "]",
                s -> s + s
        );
        UnaryOperator<String> f = stringMappers.reduce(
                s -> s,
                (a, b) -> a.andThen(b)::apply
        );
        System.out.println(f.apply("foo"));
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24006489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档