0

Given Guava Immutable table, i need to process all cell and and filter out some cells based on some mapper result which returns Java Optional,

  immutbleTable.cellSet()
            .parallelStream()
                .map(cell -> processAndGetOptionalResult(cell))
                .filter(cell -> cell.isPresent())
                .map(cell -> cell.get())
                .collect(Collector.of(
                        ImmutableTable.Builder::new,
                        ImmutableTable.Builder::put,
                        (l, r) -> l.putAll(r.build()),
                        ImmutableTable.Builder<String,String,String>::build)
            );
    }

Is there a better way to achieve this ? Is there a way that i can remove "map(cell -> cell.get())" and collect cell.get() via accumulator itself?

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
sidss
  • 923
  • 1
  • 12
  • 20

2 Answers2

3

Besides using method references:

immutbleTable.cellSet()
        .parallelStream()
            .map(this::processAndGetOptionalResult)
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collector.of(
                    ImmutableTable.Builder::new,
                    ImmutableTable.Builder::put,
                    (l, r) -> l.putAll(r.build()),
                    ImmutableTable.Builder<String,String,String>::build)
        );
}

the answer is no - in current (JDK 8) API there is no better way to achieve that. In JDK 9 Optional will have .stream() method, which will allow using one operation - flatMap:

immutbleTable.cellSet()
        .parallelStream()
            .map(this::processAndGetOptionalResult)
            .flatMap(Optional::stream)
            .collect(Collector.of(
                    ImmutableTable.Builder::new,
                    ImmutableTable.Builder::put,
                    (l, r) -> l.putAll(r.build()),
                    ImmutableTable.Builder<String,String,String>::build)
        );
}

For more details see this answer.

Community
  • 1
  • 1
Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112
2

You can integrate the processing of the Optional into the Collector:

resultTable = immutableTable.cellSet().parallelStream()
    .map(cell -> processAndGetOptionalResult(cell))
    .collect(Collector.of(
            ImmutableTable.Builder::new,
            (b,o) -> o.ifPresent(b::put),
            (l, r) -> l.putAll(r.build()),
            ImmutableTable.Builder<String,String,String>::build)
    );

This works smoothly as the accumulator function represents an action and performing an action (if not empty) is one of the canonical use cases for an Optional, unlike the isPresent-get sequence.

Holger
  • 285,553
  • 42
  • 434
  • 765