{"id":701,"date":"2026-06-25T23:33:40","date_gmt":"2026-06-25T22:33:40","guid":{"rendered":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=701"},"modified":"2026-07-07T23:34:09","modified_gmt":"2026-07-07T22:34:09","slug":"null-safety-mit-jspecify-nullaway-npes-zur-compile-time-verhindern","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=701","title":{"rendered":"Null-Safety mit JSpecify &amp; NullAway \u2013 NPEs zur Compile-Time verhindern"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><code>NullPointerException<\/code>&nbsp;\u2014 der ungeliebte Dauergast jeder Java-Codebase. Tony Hoare nannte seine Erfindung der Null-Referenz einmal seinen \u201eMilliarden-Dollar-Fehler&#8220;. Moderne Sprachen wie Kotlin und Swift l\u00f6sen das mit nicht-nullbaren Typen \u2014 Java selbst aber nicht.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Zwei Werkzeuge \u00e4ndern das:&nbsp;<strong>JSpecify 1.0<\/strong>&nbsp;als standardisierte Annotationen und&nbsp;<strong>NullAway<\/strong>&nbsp;als Compile-Time-Checker von Uber. Dieser Artikel zeigt, wie du beide kombinierst, um NPEs zu elimieren, bevor sie jemals in Produktion laufen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Das Problem: Fragmentierte @Nullable-Landschaft<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Jeder definiert&nbsp;<code>@Nullable<\/code>&nbsp;selbst:&nbsp;<code>javax.annotation<\/code>,&nbsp;<code>org.jetbrains.annotations<\/code>,&nbsp;<code>org.checkerframework.checker.nullness.qual<\/code>,&nbsp;<code>edu.umd.cs.findbugs.annotations<\/code>, &#8230; Keines dieser Annotations ist standardisiert, und keines verh\u00e4lt sich tool-\u00fcbergreifend konsistent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>JSpecify 1.0.0<\/strong>&nbsp;(Juli 2024) l\u00f6st das: Ein Konsortium aus Google, Uber, JetBrains und Oracle hat sich auf&nbsp;<strong>vier<\/strong>&nbsp;Nullness-Annotationen mit pr\u00e4ziser Semantik geeinigt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">JSpecify: Die vier Annotationen<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> org.jspecify.annotations.*;\n\n@NullMarked   &lt;em&gt;<span class=\"hljs-comment\">\/\/ Alle nicht-annotierten Typen in diesem Scope sind @NonNull&lt;\/em&gt;<\/span>\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">BenutzerService<\/span> <\/span>{\n\n    &lt;em&gt;<span class=\"hljs-comment\">\/\/ @Nullable auf Typs \u2014 der R\u00fcckgabetyp kann null sein&lt;\/em&gt;<\/span>\n    public @Nullable Benutzer findeNachEmail(<span class=\"hljs-built_in\">String<\/span> email) {\n        <span class=\"hljs-keyword\">return<\/span> benutzerDb.get(email);  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ darf null zur\u00fcckgeben<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n\n    &lt;em&gt;<span class=\"hljs-comment\">\/\/ Ohne @Nullable: @NonNull implizit \u2014 der Parameter darf nicht null sein&lt;\/em&gt;<\/span>\n    public <span class=\"hljs-keyword\">void<\/span> aktualisiereEmail(Benutzer benutzer, <span class=\"hljs-built_in\">String<\/span> neueEmail) {\n        benutzer.setEmail(neueEmail);  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ NPE-safe: benutzer ist garantiert nicht null<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Annotation<\/th><th class=\"has-text-align-left\" data-align=\"left\">Zweck<\/th><\/tr><\/thead><tbody><tr><td><code>@Nullable<\/code><\/td><td>Type-Use: Dieser Typ kann&nbsp;<code>null<\/code>&nbsp;sein<\/td><\/tr><tr><td><code>@NullMarked<\/code><\/td><td>Scope: Alles in diesem Bereich ist default&nbsp;<code>@NonNull<\/code><\/td><\/tr><tr><td><code>@NullUnmarked<\/code><\/td><td>Scope: Hebt&nbsp;<code>@NullMarked<\/code>&nbsp;f\u00fcr einen Teilbereich auf (inkrementelle Migration)<\/td><\/tr><tr><td><code>@NonNull<\/code><\/td><td>Type-Use: Explizit nicht null (meist redundant, da Default)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Wichtig:&nbsp;<code>@NullMarked<\/code>&nbsp;gilt f\u00fcr Parameter, R\u00fcckgabewerte und Felder \u2014&nbsp;<strong>nicht<\/strong>&nbsp;f\u00fcr lokale Variablen (diese sind durch Flow-Typisierung automatisch erfasst).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">NullAway: Der Compile-Time-Enforcer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">NullAway (aktuell&nbsp;<strong>0.13.7<\/strong>) ist ein Error-Prone-Plugin, das Null-Verletzungen zur Compile-Zeit erkennt \u2014 ohne Laufzeit-Overhead. Anders als der Checker Framework (vollst\u00e4ndig, aber langsam) verfolgt NullAway einen&nbsp;<strong>pragmatischen<\/strong>&nbsp;Ansatz: Es erkennt ~95% aller NPEs mit weniger als 10% Build-Zeit-Overhead.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Setup mit Gradle (empfohlen)<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">plugins {\n    id <span class=\"hljs-string\">'java'<\/span>\n    id <span class=\"hljs-string\">'net.ltgt.errorprone'<\/span> version <span class=\"hljs-string\">'5.1.0'<\/span>\n}\n\ndependencies {\n    errorprone <span class=\"hljs-string\">'com.uber.nullaway:nullaway:0.13.7'<\/span>\n    errorprone <span class=\"hljs-string\">'com.google.errorprone:error_prone_core:2.50.0'<\/span>\n    api <span class=\"hljs-string\">'org.jspecify:jspecify:1.0.0'<\/span>\n}\n\ntasks.withType(JavaCompile).configureEach {\n    options.errorprone {\n        check(<span class=\"hljs-string\">'NullAway'<\/span>, CheckSeverity.ERROR)\n        option(<span class=\"hljs-string\">'NullAway:AnnotatedPackages'<\/span>, <span class=\"hljs-string\">'com.meinefirma'<\/span>)\n        option(<span class=\"hljs-string\">'NullAway:JSpecifyMode'<\/span>, <span class=\"hljs-string\">'true'<\/span>)\n    }\n    <span class=\"hljs-keyword\">if<\/span> (name.toLowerCase().contains(<span class=\"hljs-string\">'test'<\/span>)) {\n        options.errorprone.disable(<span class=\"hljs-string\">'NullAway'<\/span>)\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Setup mit Maven<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependencies<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.jspecify<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>jspecify<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>1.0.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependencies<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">build<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">plugins<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">plugin<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.apache.maven.plugins<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>maven-compiler-plugin<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>3.13.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">configuration<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">compilerArgs<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">arg<\/span>&gt;<\/span>-Xplugin:ErrorProne\n                        -Xep:NullAway:ERROR\n                        -XepOpt:NullAway:AnnotatedPackages=com.meinefirma\n                        -XepOpt:NullAway:JSpecifyMode=true<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">arg<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">compilerArgs<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">annotationProcessorPaths<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">path<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>com.google.errorprone<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>error_prone_core<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>2.50.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">path<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">path<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>com.uber.nullaway<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>nullaway<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>0.13.7<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">path<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">annotationProcessorPaths<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">configuration<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">plugin<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">plugins<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">build<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Was NullAway erkennt<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">NullAway f\u00fchrt eine&nbsp;<strong>intra-prozedurale Datenflussanalyse<\/strong>&nbsp;durch und findet diese typischen Fehler:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Bug 1: null \u00fcbergeben, wo @NonNull erwartet wird<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">@NullMarked\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Validierung<\/span> <\/span>{\n    <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-built_in\">String<\/span> sichereLaenge(<span class=\"hljs-built_in\">String<\/span> s) {\n        <span class=\"hljs-keyword\">return<\/span> s.length() + <span class=\"hljs-string\">\" Zeichen\"<\/span>;  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ NPE-safe: s ist @NonNull<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n\n    <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> test() {\n        sichereLaenge(<span class=\"hljs-literal\">null<\/span>);  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ \u274c COMPILE-ERROR: @Nullable an @NonNull \u00fcbergeben<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Bug 2: @Nullable dereferenzieren ohne Null-Check<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">@NullMarked\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Validierung<\/span> <\/span>{\n    <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> log(@Nullable <span class=\"hljs-built_in\">Object<\/span> x) {\n        System.out.println(x.toString());  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ \u274c COMPILE-ERROR: x ist @Nullable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n\n    <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> logFixed(@Nullable <span class=\"hljs-built_in\">Object<\/span> x) {\n        <span class=\"hljs-keyword\">if<\/span> (x != <span class=\"hljs-literal\">null<\/span>) {\n            System.out.println(x.toString());  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ \u2705 OK: Datenfluss erkennt x \u2260 null<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n        }\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Bug 3: @NonNull-Feld nicht initialisiert<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">@NullMarked\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Person<\/span> <\/span>{\n    <span class=\"hljs-built_in\">String<\/span> name;  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ @NonNull implizit<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n\n    Person() {}  &lt;em&gt;<span class=\"hljs-comment\">\/\/ \u274c COMPILE-ERROR: Field 'name' nicht initialisiert&lt;\/em&gt;<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Bug 4: @Nullable aus @NonNull-Methode zur\u00fcckgeben<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">@NullMarked\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Factory<\/span> <\/span>{\n    @Nullable <span class=\"hljs-built_in\">String<\/span> vielleichtNull() { <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">null<\/span>; }\n\n    <span class=\"hljs-built_in\">String<\/span> garantiertNichtNull() {\n        <span class=\"hljs-keyword\">return<\/span> vielleichtNull();  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ \u274c COMPILE-ERROR<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Inkrementelle Migration mit @NullUnmarked<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bestehende Codebasen migriert man schrittweise:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">@NullUnmarked  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Altes Package: Keine Pr\u00fcfungen<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\npackage com.meinefirma.legacy;\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ ---<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n\n@NullMarked    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Neues Package: Volle Pr\u00fcfungen<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\npackage com.meinefirma.buchhaltung;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">NullAway&#8217;s Option&nbsp;<code>NullAway:OnlyNullMarked<\/code>&nbsp;pr\u00fcft automatisch nur&nbsp;<code>@NullMarked<\/code>-Scopes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">JSpecify und Kotlin<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ein gro\u00dfer Vorteil von JSpecify: Kotlin liest die Annotationen direkt. Wenn du eine Java-Bibliothek mit&nbsp;<code>@NullMarked<\/code>&nbsp;annotierst, erkennt der Kotlin-Compiler deren Nullness-Signaturen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Java-Klasse mit JSpecify:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ @NullMarked<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ public class Calculator {<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/     public @Nullable String format(int n) { ... }<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ }<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Kotlin-Consumer erkennt automatisch:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nval result: String? = Calculator().format(42)  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ ? nullable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Ohne JSpecify w\u00e4re es String! (platform type) \u2192 keine Pr\u00fcfung<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Vergleich der Tools<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\"><\/th><th class=\"has-text-align-left\" data-align=\"left\">NullAway + JSpecify<\/th><th class=\"has-text-align-left\" data-align=\"left\">Checker Framework<\/th><th class=\"has-text-align-left\" data-align=\"left\">IntelliJ Inspections<\/th><\/tr><\/thead><tbody><tr><td><strong>Standardisiert<\/strong><\/td><td>Ja (JSpecify 1.0)<\/td><td>Nein<\/td><td>Nein<\/td><\/tr><tr><td><strong>Build-Zeit-Overhead<\/strong><\/td><td>&lt;10%<\/td><td>Erheblich<\/td><td>Keiner (nur IDE)<\/td><\/tr><tr><td><strong>Erkennt<\/strong><\/td><td>~95%<\/td><td>100% (sound)<\/td><td>~80% (Heuristiken)<\/td><\/tr><tr><td><strong>Kotlin-Interop<\/strong><\/td><td>Ja<\/td><td>Nein<\/td><td>Teilweise<\/td><\/tr><tr><td><strong>Inkrementell<\/strong><\/td><td>Ja (@NullUnmarked)<\/td><td>Ja (@SuppressWarnings)<\/td><td>Immer aktiv<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">JSpecify und NullAway zusammen geben Java das, was Kotlin und Swift von Haus aus haben: Compile-Time-Null-Safety. Der Setup-Aufwand ist minimal (eine Dependency, eine Annotation), der Gewinn immens: Keine&nbsp;<code>NullPointerException<\/code>&nbsp;in annotiertem Code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Beginne mit neuen Packages unter&nbsp;<code>@NullMarked<\/code>&nbsp;und migriere bestehenden Code schrittweise. In einem Jahr wirst du dich fragen, wie du jemals ohne leben konntest.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>NullPointerException&nbsp;\u2014 der ungeliebte Dauergast jeder Java-Codebase. Tony Hoare nannte seine Erfindung der Null-Referenz einmal seinen \u201eMilliarden-Dollar-Fehler&#8220;. Moderne Sprachen wie Kotlin und Swift l\u00f6sen das mit nicht-nullbaren Typen \u2014 Java selbst aber nicht. Zwei Werkzeuge \u00e4ndern das:&nbsp;JSpecify 1.0&nbsp;als standardisierte Annotationen und&nbsp;NullAway&nbsp;als Compile-Time-Checker von Uber. Dieser Artikel zeigt, wie du beide kombinierst, um NPEs zu elimieren, bevor [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-701","post","type-post","status-publish","format-standard","hentry","category-plain_java"],"_links":{"self":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=701"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/701\/revisions"}],"predecessor-version":[{"id":702,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/701\/revisions\/702"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}