有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java将列表缩减为回退链

假设我有一个Java中一些实体的列表,比如

List<Entity> entities = Arrays.asList(entity1, entity2, entity3...);

我想将其简化为一个链对象的实例,如:

class EntityChain {
    private final Entity entity;
    private final Optional<EntityChain> fallback;

    private EntityChain(Builder builder) {
        this.entity = builder.entity;
        this.fallback = builder.fallback;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static final class Builder {
        private Entity entity;
        private Optional<EntityChain> fallback = Optional.empty();           

        public Builder withEntity(Entity entity) {
            this.entity = entity;
            return this;
        }

        public Builder withFallback(EntityChain fallback) {
            this.fallback = Optional.of(fallback);
            return this;
        }

        public EntityChain build() {
            return new EntityChain(this);
        }
    }
}

EntityChain是不可变的,并且有一个生成器
因此,结果将是一个EntityChain实例,如:

chain
   -> entity = entity1
   -> fallback
        -> entity = entity2
        -> fallback
            -> entity = entity3
            -> fallback
                ...

有没有可能通过一些神奇的Java8Fluent简化来实现这一点

Stream.reduce(U identity,
              BiFunction<U, ? super T, U> accumulator,
              BinaryOperator<U> combiner)

适用于这里吗?以某种方式使用它的生成器


共 (3) 个答案

  1. # 1 楼答案

    经过思考,我发现在顺序流中减少时,我可以完全移除holderSupplier<EntityChain>。该算法是逆向构建实体链:首先构建实体(n),然后构建实体(n-1)。。。实体(0)

    BiFunction<EntityChain, Entity, EntityChain> reducing =
        (next, entity) -> Optional.ofNullable(next)
                        // create a builder with fallback if EntityChain present
                        .map(fallback -> EntityChain.builder().withFallback(fallback))
                        // create a builder without fallback
                        .orElseGet(EntityChain::builder)
                        //build the EntityChain
                        .withEntity(entity).build();
    
    // combiner never be used in sequentially stream
    BinaryOperator<EntityChain> rejectedInParallelStream = (t1, t2) -> {
        //when you use parallel the chain order maybe changed, and the result is wrong.
        throw new IllegalStateException("Can't be used in parallel stream!");
    };
    
    
    EntityChain chain = reverse(entities).
            stream().reduce(null, reducing, rejectedInParallelStream);
    
    
    //copy & reverse the copied List
    static <T> List<T> reverse(List<T> list) {
        List<T> it = list.stream().collect(Collectors.toList());
        Collections.reverse(it);
        return it;
    }
    

    输出

    -> entity = entity1
    -> fallback
        -> entity = entity2
        -> fallback (empty)
    
  2. # 2 楼答案

    为了将列表简化为生成器,需要一个累加器(Builder::withEntity)和一个组合器(Builder::combine):

    public class ChainBuilder {
    
      public static class Entity {
        int data;
        public Entity(int i) {
          data = i;
        }
        @Override
        public String toString() {
          return "Entity [data=" + data + "]";
        }
      }
    
      public static class EntityChain {
        private Entity entity;
        private Optional<EntityChain> fallback = null;
    
        @Override
        public String toString() {
          return "EntityChain [entity=" + entity + ", fallback=" + fallback + "]";
        }
    
        public static class Builder {
          private EntityChain chain = null;
    
          public Builder() { }
    
          private static EntityChain newChainLink(Entity e){
            EntityChain n = new EntityChain();
            n.entity = e;
            n.fallback = Optional.empty();
            return n;
          }
    
          /** accumulator, attaches to the end of the chain */
          public Builder withEntity(Entity e) {
            if(chain == null) {
              chain = newChainLink(e);
            } else {
              EntityChain last = getLast();
              last.fallback = Optional.of(newChainLink(e));
            }
            return this;
          }
    
          /** combiner, glues two chains together */
          public Builder combine(Builder u) {
            if(u.chain != null) {
              getLast().fallback = Optional.of(u.chain);
            }
            return this;
          }
    
    
          /** returns the end of the chain */
          private EntityChain getLast() {
            EntityChain link = chain;
            while(link.fallback.isPresent()){
              link = link.fallback.get();
            }
            return link;
          }
    
          public EntityChain build() {
            return chain;
          }
    
        }
      }
    
      public static void main(String[] args) {
        List<Entity> entities = Arrays.asList(new Entity(1), new Entity(2), new Entity(3));
        final Builder reduced = entities.stream().reduce(new EntityChain.Builder(),
                                                         (t,u)->t.withEntity(u),
                                                         (t,u)->t.combine(u));
        System.out.println(reduced.build());
      }
    }
    

    这张照片是:

    EntityChain [entity=Entity [data=1], fallback=Optional[EntityChain [entity=Entity [data=2], fallback=Optional[EntityChain [entity=Entity [data=3], fallback=Optional.empty]]]]]

  3. # 3 楼答案

    您可以在需要时懒散地构建EntityChain。我用Supplier<EntityChain>完成它

    BiFunction<Supplier<EntityChain>, Entity, Supplier<EntityChain>> reducing =
        (initializer, entity) ->
                // get the EntityChain instance when get() called.
                () -> Optional.ofNullable(initializer.get())
                        // create a builder with fallback if EntityChain present
                        .map(fallback -> EntityChain.builder().withFallback(fallback))
                        // create a builder without fallback
                        .orElseGet(EntityChain::builder)
                        //build the EntityChain
                        .withEntity(entity).build();
    
    // combiner never be used in sequentially stream
    BinaryOperator<Supplier<EntityChain>> rejectedInParallelStream = (t1, t2) -> {
        throw new IllegalStateException("Can't be used in parallel stream!");
    };
    
    EntityChain chain = reverse(entities).
            stream().reduce(() -> null, reducing, rejectedInParallelStream)
            //when the initializer chain built/reduced,
            //calling the get() to fetch EntityChain header
            .get();
    
    //copy & reverse the copied List
    static <T> List<T> reverse(List<T> list) {
        List<T> it = list.stream().collect(Collectors.toList());
        Collections.reverse(it);
        return it;
    }
    

    输出

    -> entity = entity1
    -> fallback
        -> entity = entity2
        -> fallback (empty)