EDIT following the comment "Just tested, and one card got pulled twice... Need to pick 5 different, random cards."
One approach would be to use streams, and generate random numbers, more specifically primitive streams.
There are some ways of generating random numbers, I think that it looks cleaner it using ThreadLocalRandom, for more information about the difference of generating random numbers with Random.java and ThreadLocalRandom, there's this article talking about it
differente between Random class and ThreadLocalRandom class
For example, in your case you could use the ints() method, that has different signatures.
- we can bound the random numbers to be in the range of the deck list, so we can randomly get any card inside of it, so we would need a list with these indexes
- we can generate an unlimited stream of pseudorandom int values
- filter them to only those who are in the range of the deck indexes list
- discard the duplicate ones
- limit them to the n bound that you're going to pass wo dealHand(int n)
It fits this signature of ints()
ThreadLocalRandom.java
/**
* Returns an effectively unlimited stream of pseudorandom {@code
* int} values, each conforming to the given origin (inclusive) and bound
* (exclusive).
*
* @implNote This method is implemented to be equivalent to {@code
* ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
*
* @param randomNumberOrigin the origin (inclusive) of each random value
* @param randomNumberBound the bound (exclusive) of each random value
* @return a stream of pseudorandom {@code int} values,
* each with the given origin (inclusive) and bound (exclusive)
* @throws IllegalArgumentException if {@code randomNumberOrigin}
* is greater than or equal to {@code randomNumberBound}
* @since 1.8
*/
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
...
}
Implementing it on your example
public static List<PlayingCard> dealHand(int n){
// list with indexes of the deck list
List<Integer> deckIndexes = deck
.stream()
.map(deck::indexOf)
.collect(toList());
return ThreadLocalRandom
.current()
.ints(0, deck.size())
.filter(deckIndexes::contains)
.distinct()
.limit(n)
.mapToObj(deck::get)
.collect(toList());
}
.map(deck::indexOf) maps the deck list into a list with all of its indexes
.ints() returns a IntStream with the values bounded by 0 and deck.size() and unlimited size
filter(deckIndexes::contains) filters the list to a list with values in the bound of the deckIndexes list values
distinct() returns a stream of non duplicate values of the just filtered stream
mapToObj() is a method from IntStream.java that recieves a IntFunction functional interface, that needs to be a lambda that takes an int as parameter and a R of return type
limit(n) truncate the stream to be no longer than n size
.collect() is the terminal operation that returns a Collection(of List in this case)
Syou said you wanted lambdas, you can substitute the method references used above to
.map(card -> deck.indexOf(card))
...
.filter(randomInt -> deckIndexes.contains(randomInt))
...
.mapToObj(deckIndex -> deck.get(deckIndex))