14

I have a Card class

public class Card {

   private int value, suit;

   public Card(int value, int suit) {
       this.value = value;
       this.suit = suit;
   }

   //gets, sets, toString
}

This is how I would normally fill the ArrayList of Card

for(int suit = 1; suit <= 4; ++suit)
    for(int value = 1; value <= 13; ++value)
        Cards.add(new Card(value, suit));

But I want to use a Lambda expression to initialize it

ArrayList<Card> Cards = IntStream.range(1, 4)
                           .map(value -> IntStream.range(1, 13)
                               .map(suit -> new Card(value, suit)));

Intellij is giving me an error under .map(suit -> new Card(suit, value))

It says "Incompatible return type Card in lambda expression"

2
  • 5
    I would personally keep using the old Java 7 style here, this situation does not suit that well for stream usage. Commented Mar 26, 2014 at 7:44
  • If this were a real application I would probably do that, but I'm just doing this to better learn Lambdas. Commented Mar 26, 2014 at 13:17

2 Answers 2

30

This is what you want:

List<Card> cards = IntStream.rangeClosed(1, 4)
    .boxed()
    .flatMap(value -> 
        IntStream.rangeClosed(1, 13)
            .mapToObj(suit -> new Card(value, suit))
    )
    .collect(Collectors.toList());

Points to note:

  • you have to box the ints because flatMap on primitives doesn't have any type-conversion overloads like flatMapToObj (doesn't exist);

  • assign to List rather than ArrayList as the Collectors methods make no guarantee as to the specific type they return (as it happens it currently is ArrayList, but you can't rely on that);

  • use rangeClosed for this kind of situation.

Sign up to request clarification or add additional context in comments.

1 Comment

Added a answer based on the idea that IntStream::flatMapToObj(IntFunction<Stream<OBJ>>) is equivalent to IntStream::mapToObj(IntFunction<Stream<OBJ>>) then Stream::flatMap(Function<Stream<OBJ>, Stream<OBJ>>).
6

Another way to get what you want (based on Maurice Naftalin's answer):

List<Card> cards = IntStream.rangeClosed(1, 4)
  .mapToObj(value -> IntStream.rangeClosed(1, 13)
    .mapToObj(suit -> new Card(value, suit))
  )
  .flatMap(Function.identity())
  .collect(Collectors.toList())
;

Additional points to note:

  • you have to map the int values to Stream streams, then flatMap said streams via Function.identity(), since flatMapToObj does not exists, yet said operation is translatable to a map to Stream, then an identity flatMap.

1 Comment

I like this better than my solution, even though @skiwi's comment above still stands—the imperative version is still better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.