【问题标题】:Spring WebFlux Reactor - Updating Object In FluxSpring WebFlux Reactor - 在 Flux 中更新对象
【发布时间】:2019-11-05 16:24:13
【问题描述】:

给定以下方法:

Flux<Person> getAllPerson(Criteria criteria) 

如何通过更改通量中每个 Person 对象中的字段来处理通量?

getAllPerson(criteria)
                .map(person -> person.setLastUpdated(new Date())

setLastUpdated(new Date()) 返回 void

我尝试了很多不同的方法,但我无法弄清楚如何编译它,例如:

getAllPerson(criteria)
                .map(person -> {
                     person.setLastUpdated(new Date())
                     return person;
                 });

【问题讨论】:

  • 对于标准 Streams,我会使用 peek(),但我不确定 project-reactor 是否提供类似的功能。
  • 我仍然想返回人员流量(更新日期)
  • 似乎是什么问题? peek() 这样做。

标签: java reactive-programming spring-webflux project-reactor reactive


【解决方案1】:

您可以使用doOnNext 运算符来执行这种副作用操作。

虽然,通常保持 Person 类不可变是一种更好的方法,当您需要修改某些内容时,您只需创建它的副本,在这种情况下,您将能够按预期使用 map 运算符。

【讨论】:

    【解决方案2】:

    你的第二个例子:

    getAllPerson(criteria)
                .map(person -> {
                     person.setLastUpdated(new Date())
                     return person;
                 });
    

    ...不会编译,只是因为它在 setLastUpdated() 行上缺少分号。

    然而,到目前为止,最好的事情(正如已经建议的那样)是使您的 Person 类不可变。然后,您可以使用 "wither" pattern(使用 lombok 或您自己的实现)简单地执行以下操作:

    getAllPerson(criteria)
                .map(person -> person.withLastUpdated(new Date()));
    

    如果您不能使Person 不可变(或者因为它是一个外部库,或者它的可变性太融入现有代码),那么一切都不会丢失。你仍然可以很容易地生成一个不可变的包装器,例如:

    class ImmutablePerson {
        Person person;
    
        public ImmutablePerson(Person p) {
            this.person = p;
        }
    
        public Person withFirstName(String name) {
            return new Person(name, person.getLastName(), person.getLastUpdated());
        }
    
        public Person withLastName(String name) {
            return new Person(person.getFirstName(), name, person.getLastUpdated());
        }
    
        public Person withLastUpdated(Date date) {
            return new Person(person.getFirstName(), person.getLastName(), date);
        }
    
        public String getFirstName() {return person.getFirstName();}
        public String getLastName() {return person.getLastName();}
        public Date getLastUpdated() {return person.getLastUpdated();}
        public Person toPerson() {return new Person(person.getFirstName(), person.getLastName(), person.getLastUpdated());}
    }
    

    然后,您可以在反应链的第一步中映射到 ImmutablePerson,如下所示:

    getAllPerson(criteria)
            .map(ImmutablePerson::new)
            .map(p -> p.withLastUpdated(new Date()))
            //etc.
    

    【讨论】:

    • 命令式的方式非常简单。除了使对象不可变之外没有其他方法吗
    • @user1955934 您可以仍然使用您拥有的map() 调用或使用doOnNext() 的可变对象,正如Martin 所建议的那样。哎呀,您甚至可以更改 setter 的定义以返回 this 如果它只是您所追求的干净语法。我只是不建议混合可变对象和反应流,因为它可能会在未来导致一些相当难以追踪/讨厌的错误。
    猜你喜欢
    • 1970-01-01
    • 2021-06-22
    • 1970-01-01
    • 2018-09-09
    • 2018-12-12
    • 1970-01-01
    • 2022-06-05
    • 2019-05-18
    • 2019-01-11
    相关资源
    最近更新 更多