Both are terms whose type is the intersection of all types (uninhabited). Both can be passed around in code without failing until one attempts to evaluate them. The only difference I can see is that in Java, there is a loophole which allows null to be evaluated for exactly one operation, which is reference equality comparison (==)--whereas in Haskell undefined can't be evaluated at all without throwing an exception. Is this the only difference?
Edit
What I'm really trying to get at with this question is, why was including null in Java such an apparently poor decision, and how does Haskell escape it? It seems to me that the real problem is that you can do something useful with null, namely you can check it for nullness. Because you are allowed to do this, it has become standard convention to pass around null values in code and have them indicate "no result" instead of "there is a logical error in this program". Whereas in Haskell, there's no way to check if a term evaluates to bottom without evaluating it and the program exploding, so it could never be used in such a way to indicate "no result". Instead, one is forced to use something like Maybe.
Sorry if it seems like I'm playing fast and loose with the term "evaluate"... I'm trying to draw an analogy here and having trouble phrasing it precisely. I guess that's a sign that the analogy is imprecise.