Java将列表减少到后备链

时间:2017-04-27 11:55:07

标签: java java-8 java-stream reduce chain

假设我有一些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
                ...

是否可以通过一些神奇的Java 8流畅减少来实现这一目标? 是

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

适用于此?以某种方式使用它的构建者?

3 个答案:

答案 0 :(得分:2)

在思考之后,我发现在顺序流中减少时我可以完全删除持有者Supplier<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)

答案 1 :(得分:1)

您可以在需要时通过延迟构建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)

答案 2 :(得分:0)

为了将列表缩减为构建器,您需要一个累加器(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] ]]]]

相关问题