The best thing of all to do with exceptions is to prevent them from propagating. Sometimes this is impossible, sometimes it’s easy, and sometimes it requires a bit of creativity.
In the case of Deck, I think we’re at the point where we simply don’t care too much. If programmers want to write bad client code that deals from an empty deck, that’s their problem. I like to categorize exceptions into two types: those that are controllable via client code, and those that are not. For example, acquiring a connection to an external resource usually can’t be controlled. The empty deck exception is certainly controllable; we do so by writing good client code within the poker application. Why would we write code that attempts to deal from an empty deck?
One solution would be not to throw an exception at all, perhaps returning a null card. Ultimately this would propagate a NullPointerException. The problem I have with that solution is that it makes debugging more difficult because the NullPointerException is usually generated at a later point in code execution. Generating and throwing a custom RuntimeException at the point of failure makes it far easier to decipher any problems.