In it, a programming example is available, which could be rewritten using the Lambda style in Java 8.
I am going to attempt doing just that and post my results below.
ForEach
When I was following the MOOC course of Oracle1, Simon Ritter quite emphatically mentioned trying not to use the foreach method when not required.But let us try it now, as a seemingly perfectly reasonable first step on a slippery slope to hell.
What we need is a stream of random numbers, and then run the foreach on it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A quick implementation of the Martingale | |
* system of gambling. Run it, and it will | |
* play at the roulette table, until broke. | |
* How far can you make it before going | |
* broke? Let me know! | |
* | |
* @author mrbear | |
*/ | |
public class Martingale | |
{ | |
private long account = 255; | |
private long bet = 1; | |
private long maxbet = 0; | |
public void bet() | |
{ | |
IntStream ints = new Random().ints(0, 37); | |
ints.forEach(x | |
-> | |
{ | |
System.out.println("Account: " | |
+ account | |
+ " Betting " + bet | |
+ " $ on red.. result is " | |
+ x + " " | |
+ Bet.getBet(x)); | |
if (Bet.getBet(x) == Bet.RED) | |
{ | |
account += bet; | |
bet = 1; | |
} else | |
{ | |
// not red, we lose! | |
account -= bet; | |
bet *= 2; | |
if (bet > maxbet) | |
{ | |
maxbet = bet; | |
System.out.println("Maximum bet increased to " + maxbet + "$"); | |
} | |
if (account < 0) | |
{ | |
throw new RuntimeException("You now owe the casino " | |
+ (-account) + " $"); | |
} | |
} | |
}); | |
} | |
public static void main(String[] stuff) | |
{ | |
Martingale martingale = new Martingale(); | |
martingale.bet(); | |
} | |
} |
Still doesn't look very much better, and perhaps even a little bit worse.
Mapping
Let's try to make it better.For this we are going to use an "Account" class. Like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* My gambling account. | |
* | |
* @author mrbear | |
*/ | |
public class Account | |
{ | |
private long account = 255; | |
private long betSize = 1; | |
private long betCount = 1; | |
/** | |
* We win some money and start over. | |
*/ | |
public synchronized void add() | |
{ | |
account += betSize; | |
betSize = 1; | |
betCount++; | |
} | |
/** | |
* We lose the money, and double our bets. | |
*/ | |
public synchronized void subtract() | |
{ | |
// not red, we lose! | |
account -= betSize; | |
if (account < 0) | |
{ | |
throw new RuntimeException("You are broke after " + betCount + " bets! You now owe the casino " | |
+ (-account) + " $"); | |
} | |
betSize *= 2; | |
betCount++; | |
} | |
} |
This class will be used in the Lambda, like so:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A quick implementation of the Martingale | |
* system of gambling. Run it, and it will | |
* play at the roulette table, until broke. | |
* How far can you make it before going | |
* broke? Let me know! | |
* | |
* @author mrbear | |
*/ | |
public class Martingale | |
{ | |
private final Account account = new Account(); | |
public void bet() | |
{ | |
new Random() | |
.ints(0, 37) | |
.mapToObj(x -> Bet.getBet(x)) | |
.forEach(x | |
-> | |
{ | |
if (x == Bet.RED) | |
{ | |
account.add(); | |
} else | |
{ | |
account.subtract(); | |
} | |
}); | |
} | |
public static void main(String[] stuff) | |
{ | |
Martingale martingale = new Martingale(); | |
martingale.bet(); | |
} | |
} |
Conclusion
Lambdas can make your code look a lot cleaner. However, they can never replace all the loops in your code, as witnessed in the example above.I'd really like to use collect or reduce instead of the forEach in the example, but I don't think I can.
But if anyone has any suggestions on how to fix it, please tell me.
For the source code to the "Bet" class, check out https://gist.github.com/maartenl/a804f4ac435f491b57c7ae810d5fd577.
Peek and Debugging
Peek is very valuable if you wish to do some debugging of your new Lambdas.Using the following:
new Random()
.ints(0, 37)
.peek(System.out::println)
.mapToObj(x -> Bet.getBet(x))
.peek(System.out::println)
.forEach(x
->
{
if (x == Bet.RED)
{
account.add();
} else
{
account.subtract();
}
});
.ints(0, 37)
.peek(System.out::println)
.mapToObj(x -> Bet.getBet(x))
.peek(System.out::println)
.forEach(x
->
{
if (x == Bet.RED)
{
account.add();
} else
{
account.subtract();
}
});
You get some nice output to see what's happening:
10
BLACK
29
BLACK
11
BLACK
19
RED
26
BLACK
34
RED
34
RED
BLACK
29
BLACK
11
BLACK
19
RED
26
BLACK
34
RED
34
RED
References
- [1] Oracle - Announcing: JDK 8 MOOC: Lambdas and Streams!
- https://blogs.oracle.com/javatraining/entry/announcing_jdk_8_mooc_lambdas
- [2] The Java™ Tutorials > Collections > Aggregate Operations - Reduction
- https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html
- Wikipedia - Roulette
- https://en.wikipedia.org/wiki/Roulette