JDK upgradesmedium3-5 years

A team upgrading 11 to 17 compiles with `-source 11 -target 11` on the new JDK, and the build passes clean. Weeks after deploying to a fleet still running Java 11, one code path throws `NoSuchMethodError` in production. What did `-source`/`-target` fail to catch, and what should they have used instead?

-source 11 -target 11 on a Java 17 compiler only changes two things: which language syntax the parser accepts, and which class-file version gets written out. It says nothing about which APIs are safe to call — nothing stops code from calling a method that was added in, say, Java 15, while still targeting Java 11 bytecode, because the compiler is still running on the full Java 17 JDK's classpath, where that method genuinely exists. The code compiles cleanly, produces valid Java-11-format bytecode, and then throws NoSuchMethodError the moment it actually runs on a real Java 11 JVM, where that method was never added. --release 11 closes exactly this gap: instead of -source/-target's two narrower checks, it substitutes the actual Java 11 API surface for what the compiler is allowed to reference, so calling a Java-15-only method under --release 11 is a compile error, caught immediately, not a runtime surprise four months later.

The lesson behind it →