Although, I can see that doing any kind of write operation or class cast operation on s1 and s2 can lead to all kinds of exceptions, I dont understand why the above method is unsafe. Author Joshua Bloch goes on to recommend the following method instead.

It is bad in the sense that it prevents the compiler from type-checking more of your code.

Of course you can write good and safe code without it. People do it in Perl and Javascript every day. And even in Java, there is no difference between using raw types and using typed collections at runtime. But there is something to be said for having a compiler check as much as possible for you.

So, with a method like in your example, use wildcard types (Set<?>) instead of raw types. That way, if you do write "dangerous" code like s1.addAll(s2); the compiler will shout at you.