C# half-fixes this with its nullable annotations. I say half-fixes, because the boundary between code that supports them and code that does not is leaky, so you can make a mistake that leaks a null into a non-nullable variable.
If you build an entire program with nullability checking on it's pretty great, though.
Java, or at least Lombok, seems to have a @NonNull annotation that does what I want— cause code not to build that fails the check, and forces propagation of the annotation.
Reality does indeed feel exactly like what you mentioned with C#, though. The annotation is going to be missing where it’s needed most unless something forces the whole project to use it.
check JSpecify (https://jspecify.dev) - it's the standardised null annotation package for Java. Intellij understands the annotations so you generally get decent null-checking across your codebase.
Even better, apply at the package level via `package-info.java` (unfortunately sub-packages need to be individually marked as well)
If you build an entire program with nullability checking on it's pretty great, though.