Sequencing Collector for Eithers

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
4
down vote

favorite












Using Java 8, I'd like to sequence my eithers using a Collector:



Sequencing a stream of eithers means for me:



  • If there's at least one left either inside the stream, I expect the Collector to return the first left either.

  • If the eithers in the stream are exclusively right, I expect the Collector to return a list of each element inside the right eithers. That list is wrapped in a right either.

For example:



// Produces Either.Right([1, 2])
Stream.of(Either.right("1"), Either.right("2"))
.collect(sequence());

// Produces Either.Left(too bad)
Stream.<Either<String, Integer>>of(Either.right(1), Either.left("too bad"),
Either.left("no"))
.collect(sequence());


I'm using Fugue's Either type.



I came up with a solution that works for me but, oh my, the type of that thing:



/**
* Creates a @link Collector that produces the first left
* @link Either either from a @link Stream
* of @link Eithers or all the right elements if there is
* no left element in the @link Stream.
* <p>
* Note: This is untested for parallel streams.
*
* @param <L> the type of left elements in the @link Eithers
* @param <R> the type of right elements in the @link Eithers
* @return a @link Collector sequencing a @link Stream of @link Eithers
*/
public static <L, R> Collector<Either<L, R>,
List<Either<L, List<R>>>,
Either<L, List<R>>> sequence()

Supplier<String> getErrorMsg =
() -> "Couldn't get either although it is right";
// The combiner combines partial results of the collector.
// Collector demands that we use a mutable container for the either.
// We chose a list for that.
BinaryOperator<List<Either<L, List<R>>>> combiner =
(firstEitherContainer, secondEitherContainer) ->
// When both eithers are right, we combine their lists
if (firstEitherContainer.get(0).isRight() &&
secondEitherContainer.get(0).isRight())
firstEitherContainer.get(0).getOrError(getErrorMsg)
.addAll(secondEitherContainer.get(0)
.getOrError(getErrorMsg));
return firstEitherContainer;
// We found a left either -> Return that,
// throwing away the accumulated right eithers
else if (firstEitherContainer.get(0).isRight() &&
secondEitherContainer.get(0).isLeft())
return secondEitherContainer;
else
// The first either was already left, continue with that
return firstEitherContainer;

;
// The accumulator merges the elements inside the stream.
// Again, the Collector demands that we use a mutable container
// for the either, which is our list.
BiConsumer<List<Either<L, List<R>>>, Either<L, R>> accumulator =
(acc, either) ->
// Both eithers are right -> Merge their lists
if (acc.get(0).isRight() && either.isRight())
acc.get(0).forEach(rights ->
rights.add(either.getOrError(getErrorMsg)));

// We found the first left either ->
// This either is now the accumulator
else if (acc.get(0).isRight() && either.isLeft())
acc.set(0, Either.left(either.left().get()));

// The accumulator already contained a left either ->
// Leave the accumulator as it is
;
// Get the either from the list
Function<List<Either<L, List<R>>>, Either<L, List<R>>> finisher =
eithers -> eithers.get(0);

return Collector.of(
// The supplier for the start element has to be a mutable container.
// Also, the list inside the either must be mutable since we
// add other values to it.
() -> Arrays.asList(Either.right(new ArrayList<>())),
accumulator,
combiner,
finisher);



I would love to get feedback on that sequence function, especially on how to achieve the same with less code and shorter type signatures.







share|improve this question



























    up vote
    4
    down vote

    favorite












    Using Java 8, I'd like to sequence my eithers using a Collector:



    Sequencing a stream of eithers means for me:



    • If there's at least one left either inside the stream, I expect the Collector to return the first left either.

    • If the eithers in the stream are exclusively right, I expect the Collector to return a list of each element inside the right eithers. That list is wrapped in a right either.

    For example:



    // Produces Either.Right([1, 2])
    Stream.of(Either.right("1"), Either.right("2"))
    .collect(sequence());

    // Produces Either.Left(too bad)
    Stream.<Either<String, Integer>>of(Either.right(1), Either.left("too bad"),
    Either.left("no"))
    .collect(sequence());


    I'm using Fugue's Either type.



    I came up with a solution that works for me but, oh my, the type of that thing:



    /**
    * Creates a @link Collector that produces the first left
    * @link Either either from a @link Stream
    * of @link Eithers or all the right elements if there is
    * no left element in the @link Stream.
    * <p>
    * Note: This is untested for parallel streams.
    *
    * @param <L> the type of left elements in the @link Eithers
    * @param <R> the type of right elements in the @link Eithers
    * @return a @link Collector sequencing a @link Stream of @link Eithers
    */
    public static <L, R> Collector<Either<L, R>,
    List<Either<L, List<R>>>,
    Either<L, List<R>>> sequence()

    Supplier<String> getErrorMsg =
    () -> "Couldn't get either although it is right";
    // The combiner combines partial results of the collector.
    // Collector demands that we use a mutable container for the either.
    // We chose a list for that.
    BinaryOperator<List<Either<L, List<R>>>> combiner =
    (firstEitherContainer, secondEitherContainer) ->
    // When both eithers are right, we combine their lists
    if (firstEitherContainer.get(0).isRight() &&
    secondEitherContainer.get(0).isRight())
    firstEitherContainer.get(0).getOrError(getErrorMsg)
    .addAll(secondEitherContainer.get(0)
    .getOrError(getErrorMsg));
    return firstEitherContainer;
    // We found a left either -> Return that,
    // throwing away the accumulated right eithers
    else if (firstEitherContainer.get(0).isRight() &&
    secondEitherContainer.get(0).isLeft())
    return secondEitherContainer;
    else
    // The first either was already left, continue with that
    return firstEitherContainer;

    ;
    // The accumulator merges the elements inside the stream.
    // Again, the Collector demands that we use a mutable container
    // for the either, which is our list.
    BiConsumer<List<Either<L, List<R>>>, Either<L, R>> accumulator =
    (acc, either) ->
    // Both eithers are right -> Merge their lists
    if (acc.get(0).isRight() && either.isRight())
    acc.get(0).forEach(rights ->
    rights.add(either.getOrError(getErrorMsg)));

    // We found the first left either ->
    // This either is now the accumulator
    else if (acc.get(0).isRight() && either.isLeft())
    acc.set(0, Either.left(either.left().get()));

    // The accumulator already contained a left either ->
    // Leave the accumulator as it is
    ;
    // Get the either from the list
    Function<List<Either<L, List<R>>>, Either<L, List<R>>> finisher =
    eithers -> eithers.get(0);

    return Collector.of(
    // The supplier for the start element has to be a mutable container.
    // Also, the list inside the either must be mutable since we
    // add other values to it.
    () -> Arrays.asList(Either.right(new ArrayList<>())),
    accumulator,
    combiner,
    finisher);



    I would love to get feedback on that sequence function, especially on how to achieve the same with less code and shorter type signatures.







    share|improve this question























      up vote
      4
      down vote

      favorite









      up vote
      4
      down vote

      favorite











      Using Java 8, I'd like to sequence my eithers using a Collector:



      Sequencing a stream of eithers means for me:



      • If there's at least one left either inside the stream, I expect the Collector to return the first left either.

      • If the eithers in the stream are exclusively right, I expect the Collector to return a list of each element inside the right eithers. That list is wrapped in a right either.

      For example:



      // Produces Either.Right([1, 2])
      Stream.of(Either.right("1"), Either.right("2"))
      .collect(sequence());

      // Produces Either.Left(too bad)
      Stream.<Either<String, Integer>>of(Either.right(1), Either.left("too bad"),
      Either.left("no"))
      .collect(sequence());


      I'm using Fugue's Either type.



      I came up with a solution that works for me but, oh my, the type of that thing:



      /**
      * Creates a @link Collector that produces the first left
      * @link Either either from a @link Stream
      * of @link Eithers or all the right elements if there is
      * no left element in the @link Stream.
      * <p>
      * Note: This is untested for parallel streams.
      *
      * @param <L> the type of left elements in the @link Eithers
      * @param <R> the type of right elements in the @link Eithers
      * @return a @link Collector sequencing a @link Stream of @link Eithers
      */
      public static <L, R> Collector<Either<L, R>,
      List<Either<L, List<R>>>,
      Either<L, List<R>>> sequence()

      Supplier<String> getErrorMsg =
      () -> "Couldn't get either although it is right";
      // The combiner combines partial results of the collector.
      // Collector demands that we use a mutable container for the either.
      // We chose a list for that.
      BinaryOperator<List<Either<L, List<R>>>> combiner =
      (firstEitherContainer, secondEitherContainer) ->
      // When both eithers are right, we combine their lists
      if (firstEitherContainer.get(0).isRight() &&
      secondEitherContainer.get(0).isRight())
      firstEitherContainer.get(0).getOrError(getErrorMsg)
      .addAll(secondEitherContainer.get(0)
      .getOrError(getErrorMsg));
      return firstEitherContainer;
      // We found a left either -> Return that,
      // throwing away the accumulated right eithers
      else if (firstEitherContainer.get(0).isRight() &&
      secondEitherContainer.get(0).isLeft())
      return secondEitherContainer;
      else
      // The first either was already left, continue with that
      return firstEitherContainer;

      ;
      // The accumulator merges the elements inside the stream.
      // Again, the Collector demands that we use a mutable container
      // for the either, which is our list.
      BiConsumer<List<Either<L, List<R>>>, Either<L, R>> accumulator =
      (acc, either) ->
      // Both eithers are right -> Merge their lists
      if (acc.get(0).isRight() && either.isRight())
      acc.get(0).forEach(rights ->
      rights.add(either.getOrError(getErrorMsg)));

      // We found the first left either ->
      // This either is now the accumulator
      else if (acc.get(0).isRight() && either.isLeft())
      acc.set(0, Either.left(either.left().get()));

      // The accumulator already contained a left either ->
      // Leave the accumulator as it is
      ;
      // Get the either from the list
      Function<List<Either<L, List<R>>>, Either<L, List<R>>> finisher =
      eithers -> eithers.get(0);

      return Collector.of(
      // The supplier for the start element has to be a mutable container.
      // Also, the list inside the either must be mutable since we
      // add other values to it.
      () -> Arrays.asList(Either.right(new ArrayList<>())),
      accumulator,
      combiner,
      finisher);



      I would love to get feedback on that sequence function, especially on how to achieve the same with less code and shorter type signatures.







      share|improve this question













      Using Java 8, I'd like to sequence my eithers using a Collector:



      Sequencing a stream of eithers means for me:



      • If there's at least one left either inside the stream, I expect the Collector to return the first left either.

      • If the eithers in the stream are exclusively right, I expect the Collector to return a list of each element inside the right eithers. That list is wrapped in a right either.

      For example:



      // Produces Either.Right([1, 2])
      Stream.of(Either.right("1"), Either.right("2"))
      .collect(sequence());

      // Produces Either.Left(too bad)
      Stream.<Either<String, Integer>>of(Either.right(1), Either.left("too bad"),
      Either.left("no"))
      .collect(sequence());


      I'm using Fugue's Either type.



      I came up with a solution that works for me but, oh my, the type of that thing:



      /**
      * Creates a @link Collector that produces the first left
      * @link Either either from a @link Stream
      * of @link Eithers or all the right elements if there is
      * no left element in the @link Stream.
      * <p>
      * Note: This is untested for parallel streams.
      *
      * @param <L> the type of left elements in the @link Eithers
      * @param <R> the type of right elements in the @link Eithers
      * @return a @link Collector sequencing a @link Stream of @link Eithers
      */
      public static <L, R> Collector<Either<L, R>,
      List<Either<L, List<R>>>,
      Either<L, List<R>>> sequence()

      Supplier<String> getErrorMsg =
      () -> "Couldn't get either although it is right";
      // The combiner combines partial results of the collector.
      // Collector demands that we use a mutable container for the either.
      // We chose a list for that.
      BinaryOperator<List<Either<L, List<R>>>> combiner =
      (firstEitherContainer, secondEitherContainer) ->
      // When both eithers are right, we combine their lists
      if (firstEitherContainer.get(0).isRight() &&
      secondEitherContainer.get(0).isRight())
      firstEitherContainer.get(0).getOrError(getErrorMsg)
      .addAll(secondEitherContainer.get(0)
      .getOrError(getErrorMsg));
      return firstEitherContainer;
      // We found a left either -> Return that,
      // throwing away the accumulated right eithers
      else if (firstEitherContainer.get(0).isRight() &&
      secondEitherContainer.get(0).isLeft())
      return secondEitherContainer;
      else
      // The first either was already left, continue with that
      return firstEitherContainer;

      ;
      // The accumulator merges the elements inside the stream.
      // Again, the Collector demands that we use a mutable container
      // for the either, which is our list.
      BiConsumer<List<Either<L, List<R>>>, Either<L, R>> accumulator =
      (acc, either) ->
      // Both eithers are right -> Merge their lists
      if (acc.get(0).isRight() && either.isRight())
      acc.get(0).forEach(rights ->
      rights.add(either.getOrError(getErrorMsg)));

      // We found the first left either ->
      // This either is now the accumulator
      else if (acc.get(0).isRight() && either.isLeft())
      acc.set(0, Either.left(either.left().get()));

      // The accumulator already contained a left either ->
      // Leave the accumulator as it is
      ;
      // Get the either from the list
      Function<List<Either<L, List<R>>>, Either<L, List<R>>> finisher =
      eithers -> eithers.get(0);

      return Collector.of(
      // The supplier for the start element has to be a mutable container.
      // Also, the list inside the either must be mutable since we
      // add other values to it.
      () -> Arrays.asList(Either.right(new ArrayList<>())),
      accumulator,
      combiner,
      finisher);



      I would love to get feedback on that sequence function, especially on how to achieve the same with less code and shorter type signatures.









      share|improve this question












      share|improve this question




      share|improve this question








      edited May 2 at 23:12









      Jamal♦

      30.1k11114225




      30.1k11114225









      asked May 2 at 14:23









      Matthias Braun

      4291513




      4291513




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          4
          down vote



          accepted










          I agree with the answer given by Stingy. Also note that with the collector implementation you are not short-circuiting, so with a stream of a billion elements, you will still process them all even when the first element encountered is a left.



          That being said, I will comment on a thing or two for this implementation:




          • Users of your collector generally do not really care about the type of the accumulator, so you can wildcard the type instead:



            <L, R> Collector<Either<L, R>, ?, Either<L, List<R>>> sequence()



          • I would swap the checks in your combiner, it makes it more readable in my opinion:



            Either<L, List<R>> firstEither = firstEitherContainer.get(0);
            if (firstEither.isLeft())
            return firstEitherContainer;

            Either<L, List<R>> secondEither = secondEitherContainer.get(0);
            if (secondEither.isLeft())
            return secondEitherContainer;

            firstEither.getOrError(getErrorMsg).addAll(secondEither.getOrError(getErrorMsg));
            return firstEitherContainer;






          share|improve this answer



















          • 1




            Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
            – Matthias Braun
            May 2 at 16:48






          • 1




            Oh right, my bad! I had forgotten that for a second it seems :)
            – Koekje
            May 2 at 17:13






          • 1




            For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
            – Koekje
            May 2 at 17:18










          • Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
            – Matthias Braun
            May 2 at 17:31

















          up vote
          4
          down vote















          You are horrified by "the type of that thing" because you are using stream operations for something they were not meant for. The purpose of streams is to perform pre-defined operations on an arbitrary number of elements of a kind. However, you have a scenario where the operation you want to perform depends on the nature of the stream itself. I did not really inspect your code in detail, because, based on your description of what you want to do, my suggestion would be to use a different approach altogether:



          It is possible to obtain an iterator over the elements of a stream by calling iterator() on a stream (which is a terminal operation, so the stream will be consumed after creating the iterator, which means that you can obtain the iterator only once). Using that iterator, you can simply accumulate the elements inside the encountered Eithers in a List as long as they are all right eithers. If you encounter a left either, you stop iterating and return this left either. If the iterator is exhausted before you encounter a left either, you just wrap the now fully populated list in a right either and return that either.






          share|improve this answer





















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193468%2fsequencing-collector-for-eithers%23new-answer', 'question_page');

            );

            Post as a guest






























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            4
            down vote



            accepted










            I agree with the answer given by Stingy. Also note that with the collector implementation you are not short-circuiting, so with a stream of a billion elements, you will still process them all even when the first element encountered is a left.



            That being said, I will comment on a thing or two for this implementation:




            • Users of your collector generally do not really care about the type of the accumulator, so you can wildcard the type instead:



              <L, R> Collector<Either<L, R>, ?, Either<L, List<R>>> sequence()



            • I would swap the checks in your combiner, it makes it more readable in my opinion:



              Either<L, List<R>> firstEither = firstEitherContainer.get(0);
              if (firstEither.isLeft())
              return firstEitherContainer;

              Either<L, List<R>> secondEither = secondEitherContainer.get(0);
              if (secondEither.isLeft())
              return secondEitherContainer;

              firstEither.getOrError(getErrorMsg).addAll(secondEither.getOrError(getErrorMsg));
              return firstEitherContainer;






            share|improve this answer



















            • 1




              Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
              – Matthias Braun
              May 2 at 16:48






            • 1




              Oh right, my bad! I had forgotten that for a second it seems :)
              – Koekje
              May 2 at 17:13






            • 1




              For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
              – Koekje
              May 2 at 17:18










            • Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
              – Matthias Braun
              May 2 at 17:31














            up vote
            4
            down vote



            accepted










            I agree with the answer given by Stingy. Also note that with the collector implementation you are not short-circuiting, so with a stream of a billion elements, you will still process them all even when the first element encountered is a left.



            That being said, I will comment on a thing or two for this implementation:




            • Users of your collector generally do not really care about the type of the accumulator, so you can wildcard the type instead:



              <L, R> Collector<Either<L, R>, ?, Either<L, List<R>>> sequence()



            • I would swap the checks in your combiner, it makes it more readable in my opinion:



              Either<L, List<R>> firstEither = firstEitherContainer.get(0);
              if (firstEither.isLeft())
              return firstEitherContainer;

              Either<L, List<R>> secondEither = secondEitherContainer.get(0);
              if (secondEither.isLeft())
              return secondEitherContainer;

              firstEither.getOrError(getErrorMsg).addAll(secondEither.getOrError(getErrorMsg));
              return firstEitherContainer;






            share|improve this answer



















            • 1




              Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
              – Matthias Braun
              May 2 at 16:48






            • 1




              Oh right, my bad! I had forgotten that for a second it seems :)
              – Koekje
              May 2 at 17:13






            • 1




              For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
              – Koekje
              May 2 at 17:18










            • Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
              – Matthias Braun
              May 2 at 17:31












            up vote
            4
            down vote



            accepted







            up vote
            4
            down vote



            accepted






            I agree with the answer given by Stingy. Also note that with the collector implementation you are not short-circuiting, so with a stream of a billion elements, you will still process them all even when the first element encountered is a left.



            That being said, I will comment on a thing or two for this implementation:




            • Users of your collector generally do not really care about the type of the accumulator, so you can wildcard the type instead:



              <L, R> Collector<Either<L, R>, ?, Either<L, List<R>>> sequence()



            • I would swap the checks in your combiner, it makes it more readable in my opinion:



              Either<L, List<R>> firstEither = firstEitherContainer.get(0);
              if (firstEither.isLeft())
              return firstEitherContainer;

              Either<L, List<R>> secondEither = secondEitherContainer.get(0);
              if (secondEither.isLeft())
              return secondEitherContainer;

              firstEither.getOrError(getErrorMsg).addAll(secondEither.getOrError(getErrorMsg));
              return firstEitherContainer;






            share|improve this answer















            I agree with the answer given by Stingy. Also note that with the collector implementation you are not short-circuiting, so with a stream of a billion elements, you will still process them all even when the first element encountered is a left.



            That being said, I will comment on a thing or two for this implementation:




            • Users of your collector generally do not really care about the type of the accumulator, so you can wildcard the type instead:



              <L, R> Collector<Either<L, R>, ?, Either<L, List<R>>> sequence()



            • I would swap the checks in your combiner, it makes it more readable in my opinion:



              Either<L, List<R>> firstEither = firstEitherContainer.get(0);
              if (firstEither.isLeft())
              return firstEitherContainer;

              Either<L, List<R>> secondEither = secondEitherContainer.get(0);
              if (secondEither.isLeft())
              return secondEitherContainer;

              firstEither.getOrError(getErrorMsg).addAll(secondEither.getOrError(getErrorMsg));
              return firstEitherContainer;







            share|improve this answer















            share|improve this answer



            share|improve this answer








            edited May 2 at 17:13


























            answered May 2 at 15:52









            Koekje

            1,017211




            1,017211







            • 1




              Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
              – Matthias Braun
              May 2 at 16:48






            • 1




              Oh right, my bad! I had forgotten that for a second it seems :)
              – Koekje
              May 2 at 17:13






            • 1




              For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
              – Koekje
              May 2 at 17:18










            • Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
              – Matthias Braun
              May 2 at 17:31












            • 1




              Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
              – Matthias Braun
              May 2 at 16:48






            • 1




              Oh right, my bad! I had forgotten that for a second it seems :)
              – Koekje
              May 2 at 17:13






            • 1




              For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
              – Koekje
              May 2 at 17:18










            • Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
              – Matthias Braun
              May 2 at 17:31







            1




            1




            Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
            – Matthias Braun
            May 2 at 16:48




            Thanks for your feedback Koekje! singletonList() is immutable and will throw an UnsupportedOperationException whereas asList() returns a mutable list which we need in the combiner.
            – Matthias Braun
            May 2 at 16:48




            1




            1




            Oh right, my bad! I had forgotten that for a second it seems :)
            – Koekje
            May 2 at 17:13




            Oh right, my bad! I had forgotten that for a second it seems :)
            – Koekje
            May 2 at 17:13




            1




            1




            For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
            – Koekje
            May 2 at 17:18




            For my own projects I use a custom 'ByRef' class, I like how it shows its intended purpose, instead of an array/list.
            – Koekje
            May 2 at 17:18












            Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
            – Matthias Braun
            May 2 at 17:31




            Correcting my previous comment, it's the accumulator not the combiner that mutates that list using set which would throw if the list were immutable.
            – Matthias Braun
            May 2 at 17:31












            up vote
            4
            down vote















            You are horrified by "the type of that thing" because you are using stream operations for something they were not meant for. The purpose of streams is to perform pre-defined operations on an arbitrary number of elements of a kind. However, you have a scenario where the operation you want to perform depends on the nature of the stream itself. I did not really inspect your code in detail, because, based on your description of what you want to do, my suggestion would be to use a different approach altogether:



            It is possible to obtain an iterator over the elements of a stream by calling iterator() on a stream (which is a terminal operation, so the stream will be consumed after creating the iterator, which means that you can obtain the iterator only once). Using that iterator, you can simply accumulate the elements inside the encountered Eithers in a List as long as they are all right eithers. If you encounter a left either, you stop iterating and return this left either. If the iterator is exhausted before you encounter a left either, you just wrap the now fully populated list in a right either and return that either.






            share|improve this answer

























              up vote
              4
              down vote















              You are horrified by "the type of that thing" because you are using stream operations for something they were not meant for. The purpose of streams is to perform pre-defined operations on an arbitrary number of elements of a kind. However, you have a scenario where the operation you want to perform depends on the nature of the stream itself. I did not really inspect your code in detail, because, based on your description of what you want to do, my suggestion would be to use a different approach altogether:



              It is possible to obtain an iterator over the elements of a stream by calling iterator() on a stream (which is a terminal operation, so the stream will be consumed after creating the iterator, which means that you can obtain the iterator only once). Using that iterator, you can simply accumulate the elements inside the encountered Eithers in a List as long as they are all right eithers. If you encounter a left either, you stop iterating and return this left either. If the iterator is exhausted before you encounter a left either, you just wrap the now fully populated list in a right either and return that either.






              share|improve this answer























                up vote
                4
                down vote










                up vote
                4
                down vote











                You are horrified by "the type of that thing" because you are using stream operations for something they were not meant for. The purpose of streams is to perform pre-defined operations on an arbitrary number of elements of a kind. However, you have a scenario where the operation you want to perform depends on the nature of the stream itself. I did not really inspect your code in detail, because, based on your description of what you want to do, my suggestion would be to use a different approach altogether:



                It is possible to obtain an iterator over the elements of a stream by calling iterator() on a stream (which is a terminal operation, so the stream will be consumed after creating the iterator, which means that you can obtain the iterator only once). Using that iterator, you can simply accumulate the elements inside the encountered Eithers in a List as long as they are all right eithers. If you encounter a left either, you stop iterating and return this left either. If the iterator is exhausted before you encounter a left either, you just wrap the now fully populated list in a right either and return that either.






                share|improve this answer















                You are horrified by "the type of that thing" because you are using stream operations for something they were not meant for. The purpose of streams is to perform pre-defined operations on an arbitrary number of elements of a kind. However, you have a scenario where the operation you want to perform depends on the nature of the stream itself. I did not really inspect your code in detail, because, based on your description of what you want to do, my suggestion would be to use a different approach altogether:



                It is possible to obtain an iterator over the elements of a stream by calling iterator() on a stream (which is a terminal operation, so the stream will be consumed after creating the iterator, which means that you can obtain the iterator only once). Using that iterator, you can simply accumulate the elements inside the encountered Eithers in a List as long as they are all right eithers. If you encounter a left either, you stop iterating and return this left either. If the iterator is exhausted before you encounter a left either, you just wrap the now fully populated list in a right either and return that either.







                share|improve this answer













                share|improve this answer



                share|improve this answer











                answered May 2 at 15:13









                Stingy

                1,888212




                1,888212






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193468%2fsequencing-collector-for-eithers%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Python Lists

                    Aion

                    JavaScript Array Iteration Methods