I was reading this question on SO which discusses some common undefined behavior in C++, and I wondered: does Java also have undefined behaviour?

If that is the case, then what are some common causes of undefined behaviour in Java?

If not, then which features of Java make it free from such behaviours and why haven't the latest versions of C and C++ been implemented with these properties?


5 Answers 5


In Java, you can consider behavior of incorrectly synchronized program undefined.

Java 7 JLS uses word "undefined" once, in 17.4.8. Executions and Causality Requirements:

We use f|d to denote the function given by restricting the domain of f to d. For all x in d, f|d(x) = f(x), and for all x not in d, f|d(x) is undefined...

Java API documentation specifies some cases when results are undefined - for example, in (deprecated) constructor Date(int year, int month, int day):

The result is undefined if a given argument is out of bounds...

Javadocs for ExecutorService.invokeAll(Collection) state:

The results of this method are undefined if the given collection is modified while this operation is in progress...

Less formal kind of "undefined" behavior can be found for example in ConcurrentModificationException, where API docs use term "best effort":

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness...

##Appendix One of the question comments refers to an article by Eric Lippert which provides helpful introduction into topic matters: Implementation-defined behaviour.

I recommend this article for the language-agnostic reasoning, although it is worth keeping in mind that author targets C#, not Java.

Traditionally we say that a programming language idiom has undefined behaviour if use of that idiom can have any effect whatsoever; it can work the way you expect it to or it can erase your hard disk or crash your machine. Moreover, the compiler author is under no obligation to warn you about the undefined behaviour. (And in fact, there are some languages in which programs that use "undefined behaviour" idioms are permitted by the language specification to crash the compiler!)...

By contrast, an idiom that has implementation-defined behaviour is behaviour where the compiler author has several choices about how to implement the feature, and must choose one. As the name implies, implementation-defined behaviour is at least defined. For example, C# permits an implementation to throw an exception or produce a value when an integer division overflows, but the implementation must pick one. It cannot erase your hard disk...

What are some of the factors that lead a language design committee to leave certain language idioms as undefined or implementation-defined behaviours?

The first major factor is: are there two existing implementations of the language in the marketplace that disagree on the behaviour of a particular program? ...

The next major factor is: does the feature naturally present many different possibilities for implementation, some of which are clearly better than others? ...

A third factor is: is the feature so complex that a detailed breakdown of its exact behaviour would be difficult or expensive to specify? ...

A fourth factor is: does the feature impose a high burden on the compiler to analyze? ...

A fifth factor is: does the feature impose a high burden on the runtime environment? ...

A sixth factor is: does making the behaviour defined preclude some major optimization? ...

Those are just a few factors that come to mind; there are of course many, many other factors that language design committees debate before making a feature "implementation defined" or "undefined".

Above is only a very brief coverage; full article contains explanations and examples for the points mentioned in this excerpt; it is much worth reading. For example, details given for the "sixth factor" can give one an insight into motivation for many statements in Java Memory Model (JSR 133), helping to understand why some optimizations are allowed, leading to undefined behavior while others are prohibited, leading to limitations like happen-before and causality requirements.

None of the article materials is particularly new to me but I'll be damned if I ever seen it presented in such an elegant, consise and understandable way. Amazing.

  • I'll add that the JMM != underlying hardware and the end result of an executing program with regards to concurrency can vary from say an WinIntel vs a Solaris Commented Jun 22, 2012 at 9:33
  • 2
    @MartijnVerburg that's a pretty good point. Only reason why I hesitate to tag it as "undefined" is that memory model poses constraints like happen-before and causality on execution of correctly synced program
    – gnat
    Commented Jun 22, 2012 at 9:41
  • True, the spec defines how it should behave under the JMM, however, Intel et al don't always agree ;-) Commented Jun 22, 2012 at 9:49
  • @MartijnVerburg I think the main point of JMM is to prevent over-optimizing leaks from "disagreeing" processor makers. As far as I understand Java before 5.0 had this kind of headache with DEC Alpha, when speculative writes done under the hood could leak into program like "out of thin air" - hence, causality requirement went into JSR 133 (JMM)
    – gnat
    Commented Jun 22, 2012 at 9:53
  • 9
    @MartinVerburg - it is a JVM implementer's job to make sure that the JVM behaves according to the JLS/JMM spec on any supported hardware platform. If different hardware behaves differently, it is the JVM implementer's job to deal with it ... and make it work.
    – Stephen C
    Commented Jun 22, 2012 at 13:11

Off the top of my head, I don't think there is any undefined behaviour in Java, at least not in the same sense as in C++.

The reason for this is that there is a different philosophy behind Java than behind C++. A core design goal of Java was to allow programs to run unchanged across platforms, so is specification defines everything very explicitly.

In contrast, a core design goal of C and C++ is efficiency: there should not be any features (including platform independance) that cost performance even if you don't need them. To this end, the specification deliberately does not define some behaviours because defining them would cause extra work on some platforms and thus reduce performance even for people who write programs specifically for one platform and are aware of all its idiosyncracies.

There's even an example where Java was forced to retroactively introduce a limited form of undefined behaviour for exactly that reason: the strictfp keyword was introduced in Java 1.2 to allow floating point calculations to deviate from following exactly the IEEE 754 standard as the spec had previously demanded, because doing so required extra work and made all floating-point calculations slower on some common CPUs, while actually producing worse results in some cases.

  • 2
    I think it's important to note the other main goal of Java: security and isolation. I think this, too, is a reason for the lack of 'undefined' behaviour (as in C++).
    – K.Steff
    Commented Jun 22, 2012 at 10:21
  • 3
    @K.Steff: Hyper-modern C/C++ is totally unsuitable for anything remotely security related. Given int x=-1; foo(); x<<=1; hyper-modern philosophy would favor rewriting foo so that any path which doesn't exit must be unreachable. This, if foo is if (should_launch_missiles) { launch_missiles(); exit(1); } a compiler could (and according to some people should) simplify that to simply launch_missiles(); exit(1);. The traditional UB was random code execution, but that used to be bound by the laws of time and causality. New improved UB is bound by neither.
    – supercat
    Commented Apr 19, 2015 at 14:52

Java tries quite hard to exterminate undefined behaviour, precisely because of the lessons of earlier languages. For instance, class-level variables are automatically initialized; local variables are not auto-initialized for performance reasons, but there is sophisticated data-flow analysis to prevent anyone from writing a program that would be able to detect this. References are not pointers, so invalid references cannot exist, and dereferencing null causes a specific exception.

Of course there remain some behaviours that are not fully specified, and you can write unreliable programs if you assume that they are. For instance, if you iterate over a normal (non-sorted) Set, the language guarantees that you will see each element exactly once, but not in which order you will see them. The order might be the same on successive runs, or it might change; or it might stay the same as long as no other allocations occur, or as long as you don't update your JDK, etc. It is near-impossible to get rid of all such effects; for instance, you would have to explicitly order or randomize all Collections operations, and that is simply not worth the small additional un-undefined-ness.

  • References are pointers under another name
    – curiousguy
    Commented Jun 2, 2018 at 6:30
  • @curiousguy - "references" generally are assumed not to permit the use of arithmetic manipulation of their numeric value, which is often allowed for "pointers". The former is therefore a safer construct than the latter; combined with a memory management system that doesn't allow an object's storage to be reused while a valid reference to it exists, references prevent memory use errors. Pointers cannot do so, even when appropriate memory management is used.
    – Jules
    Commented Jul 6, 2018 at 9:39
  • @Jules Then it's a matter of terminology: you may call one thing a pointer or a reference, and decide to use "reference" in "safe" languages and "pointer" in languages that allow the use of pointer arithmetic and manual memory management. (AFAIK "pointer arithmetic" is only done in C/C++.)
    – curiousguy
    Commented Nov 28, 2018 at 0:00

You have to understand the "Undefined Behavior" and its origin.

Undefined Behavior means a behavior which is not defined by the standards. C/C++ have too many different compiler implementations and additional features. These additional features tied the code to the compiler. This was because there was no centralized language development. So some of the advanced features from some of the compilers became "undefined behaviors".

Whereas in Java the language specification is controlled by Sun-Oracle and there is nobody else trying to make specifications and thus no undefined behaviors.

Edited Specifically answering the Question

  1. Java is free from undefined behaviors because standards were created before compilers
  2. Modern C/C++ compilers have more/less standardized the implementations, but the features implemented before the standardization still remain tagged as "undefined behavior" because ISO kept mum on these aspects.
  • 3
    You may be right that there is no UB in Java, but even when one entity control everything, there may be reasons to have UB, so the reason you give doesn't lead to the conclusion. Commented Jun 22, 2012 at 14:09
  • 3
    Besides, both C and C++ are standardized by ISO. While there may be multiple compilers, there's just one standard at a time.
    – MSalters
    Commented Jun 22, 2012 at 14:48
  • 2
    @SarvexJatasra, I don't agree that it is the only source of UB. For instance, one UB is dereferencing dangling pointer and there are good reasons to leave it an UB in any language which hasn't a GC, even if you start your spec now. And those reasons have nothing to do with existing practice or existing compilers. Commented Jun 22, 2012 at 16:07
  • 2
    @SarvexJatasra, signed overflow is UB because the standard says explicitly so (it is even the example given with the definition of UB). Dereferencing an invalid pointer is also an UB for the same reason, the standard says so. Commented Jun 22, 2012 at 18:37
  • 2
    @bames53: None of the cited advantages would require the level of latitude hypermodern compilers are taking with UB. With the exceptions of out-of-bounds memory accesses and stack overflows, which can "naturally" induce random code execution, I can't think of any useful optimization which would require broader latitude than to say that most UB-ish operations yield indeterminate values (which might behave as though they have "extra bits") and may only have consequences beyond that if an implementation's docs expressly reserve the right to impose such; docs may give "Unconstrained behavior"...
    – supercat
    Commented Apr 15, 2015 at 20:06

Java eliminates essentially all the undefined behavior found in C/C++. (For example: Signed integer overflow, division by zero, uninitialized variables, null pointer dereference, shifting more than bit width, double-free, even "no newline at end of source code".) But Java has a few obscure undefined behaviors that are rarely encountered by programmers.

  • Java Native Interface (JNI), a way for Java to call C or C++ code. There are many ways to screw up in JNI, like getting the function signature wrong, making invalid calls to JVM services, corrupting memory, allocating/freeing stuff incorrectly, and more. I have made these mistakes before, and generally the whole JVM crashes when any one thread executing JNI code commits an error.

  • Thread.stop(), which is deprecated. Quote:

    Why is Thread.stop deprecated?

    Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.