В Java очень и очень мало неопределенного поведения, по сравнению с C / C ++, это гораздо более четко определенная платформа. Причина этого заключается в том, что компиляторы C / C ++ предназначены для создания кода для очень разных платформ, и поэтому им были предоставлены довольно широкие свободы для предотвращения слишком строгих требований, которые заставили бы компилятор создавать субоптимальный код для данной платформы.
Java пожертвовала некоторыми из них, определив почти каждое поведение очень точным способом и предоставив лишь небольшие степени свободы. Это, конечно, делает платформу более легкой в обращении.
Основная область, где происходит неопределенное поведение, - это точное время и расписание нескольких потоков (как уже упоминал Том Хоутин).
Есть несколько мест, где поведение неочевидно, хотя, поэтому оно может выглядеть неопределенным, но это не так (примеры сравнения строк, приведенные Оскаром Рейесом, являются отличным примером).
И несколько мест, где поведение определено как неопределенное (например, порядок элементов в HashMap определяется как зависящий от реализации и не должен быть постоянным).