To the extent Java correlates with bad software, IMHO the causation is more likely to be that the environments (in the vein of clueless corporate management, waterfall, http://www.halfarsedagilemanifesto.org/) are more likely to pick Java for their development.
I wonder if I will actually ever use one of those factories again in that app.
That's the point. Java, it seems, make it tempting to "overarchitect" applications into excessively generic and modular beasts early in their lives when a much simpler implementation would be perfectly adequate and much simpler to extend and maintain.
But you know what? Once we've established that you can write bad code in any language.. I'd prefer to deal with bad code in Java than almost any other language I can think of (and I've seen a fair bit). Maybe Python wins out, but I'd rather debug bad Java code than bad C++ or bad Ruby for sure.
The nice thing about Haskell is that it's really, really hard to write things that accidentally ignore purity, which eliminates a whole class of errors and bad designs. The type system only helps you if you let it, though.
I've looked at a friend's Haskell program for Huffman encoding, that used raw recursion in a undisciplined way instead of abstracting the control flow out into, say, filters, folds and maps. That was the closed I ever got to ugly Haskell.
It's not worth it.