{"id":34112,"date":"2022-12-11T17:34:33","date_gmt":"2022-12-11T16:34:33","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=34112"},"modified":"2026-06-09T12:38:25","modified_gmt":"2026-06-09T10:38:25","slug":"scoped-values","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/scoped-values\/","title":{"rendered":"Scoped Values in Java erkl\u00e4rt \u2013 mit ThreadLocal-Vergleich"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Scoped Values<\/em> wurden \u2013 zusammen mit <a href=\"\/de\/java\/virtual-threads\/\">virtuellen Threads<\/a> und <a href=\"\/de\/java\/structured-concurrency-structuredtaskscope\/\">Structured Concurrency<\/a> \u2013 in <a href=\"https:\/\/openjdk.org\/projects\/loom\/\" target=\"_blank\" rel=\"noopener\">Project Loom<\/a> entwickelt. Sie sind seit <a href=\"\/de\/java\/java-20-features\/#scoped-values-incubator-jep-429\">Java 20<\/a> als Incubator-Feature und seit <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-21-features\/#scoped-values-preview-jep-446\">Java 21<\/a> als Preview Feature im JDK enthalten. In <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/#scoped-values-jep-506\">Java 25<\/a> wurden sie finalisiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In diesem Artikel erf\u00e4hrst du:<\/p>\n\n\n\n<ul class=\"wp-block-list hc-checked-list\">\n<li>Was ist ein <em>Scoped Value<\/em>?<\/li>\n\n\n\n<li>Wie verwendet man die <code>ScopedValue<\/code>-Klasse?<\/li>\n\n\n\n<li>Wie werden <em>Scoped Values<\/em> vererbt?<\/li>\n\n\n\n<li>Was ist der Unterschied zwischen <code>ScopedValue<\/code> und <code>ThreadLocal<\/code>?<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"was-ist-ein-scoped-value\">Was ist ein Scoped Value?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Scoped Values<\/em> sind eine Form von impliziten Methodenparametern, die es erm\u00f6glichen, einen oder mehrere Werte (d. h. beliebige Objekte) an eine oder mehrere weit entfernte Methoden zu \u00fcbergeben, ohne sie als explizite Parameter zu jeder Methode in der Aufrufkette hinzuf\u00fcgen zu m\u00fcssen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Scoped Values<\/em> werden in der Regel als \u00f6ffentliche statische Felder angelegt, so dass sie von beliebigen Methoden aus abrufbar sind.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verwenden mehrere Threads dasselbe statische <code>ScopedValue<\/code>-Feld, dann kann dieses aus Sicht eines jeden Threads einen anderen Wert enthalten.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Falls du mit <code>ThreadLocal<\/code>-Variablen vertraut bist, kommt dir das sicher bekannt vor. Tats\u00e4chlich stellen <em>Scoped Values<\/em> eine moderne Alternative zu Thread Locals dar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Am besten lassen sich <em>Scoped Values<\/em> an einem Beispiel erkl\u00e4ren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"scopedvalue-beispiel\">ScopedValue Beispiel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ein klassisches Einsatzszenario ist ein Web-Framework, das bei einem eingehenden Request den User authentifiziert und die Daten des eingeloggten Users demjenigen Code, der den Request abarbeitet, zur Verf\u00fcgung stellt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das kann z. B. ganz klassisch \u00fcber ein Methodenargument funktionieren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nun kann sich in komplexen Anwendungen die Abarbeitung eines Requests \u00fcber Hunderte von Methoden erstrecken \u2013 doch die Information \u00fcber den eingeloggten User wird evtl. nur in wenigen Methoden ben\u00f6tigt. Trotzdem m\u00fcssten wir den User durch alle Methoden durchschleifen, die irgendwann zum Aufruf einer Methode f\u00fchren, f\u00fcr die der eingeloggte User relevant ist. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Im folgenden Beispiel wird der eingeloggte User vom <code>Server<\/code> \u00fcber den <code>RestAdapter<\/code> und den <code>UseCase<\/code> bis hin zum <code>Repository<\/code> durchgereicht, wo er schlie\u00dflich ausgewertet wird:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Server<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">serve<\/span><span class=\"hljs-params\">(Request request)<\/span> <\/span>{\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        User user = authenticateUser(request);\n        restAdapter.processRequest(request, user);\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">RestAdapter<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">processRequest<\/span><span class=\"hljs-params\">(Request request, User loggedInUser)<\/span> <\/span>{ \n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        UUID id = extractId(request);\n        useCase.invoke(id, loggedInUser);\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">UseCase<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">invoke<\/span><span class=\"hljs-params\">(UUID id, User loggedInUser)<\/span> <\/span>{\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        Data data = repository.getData(id, loggedInUser);\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Repository<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Data <span class=\"hljs-title\">getData<\/span><span class=\"hljs-params\">(UUID id, User loggedInUser)<\/span> <\/span>{\n        Data data = findById(id);\n        <span class=\"hljs-keyword\">if<\/span> (loggedInUser.isAdmin()) {\n            enrichDataWithAdminInfos(data);\n        }\n        <span class=\"hljs-keyword\">return<\/span> data;\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\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der zus\u00e4tzliche Parameter <code>loggedInUser<\/code> macht unseren Code sehr schnell un\u00fcbersichtlich. Die meisten der Methoden ben\u00f6tigen den User gar nicht \u2013 und es k\u00f6nnte sogar Methoden geben, denen wir aus Sicherheitsgr\u00fcnden den Zugriff auf den User gar nicht erst erlauben wollen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Und was w\u00e4re, wenn wir an einer Stelle tief im Aufruf-Stack auch noch die IP-Adresse des Users und eine Trace-ID ben\u00f6tigten? Dann m\u00fcssten wir zwei weitere Argumente durch zahllose Methoden durchschleifen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Alternative ist es, den User in einem <em>Scoped Value<\/em> zu speichern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Das funktioniert wie folgt:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wir legen an \u00f6ffentlich zug\u00e4nglicher Stelle ein statisches Feld vom Typ <code>ScopedValue<\/code> an. Mit <code>ScopedValue.where(...)<\/code> binden wir den <em>Scoped Value<\/em> an den konkreten User, und der <code>ScopedValue.run()<\/code>-Methode \u00fcbergeben wir \u2013 in Form eines&nbsp;<code>Runnable<\/code>&nbsp;\u2013 den Code, f\u00fcr dessen Aufrufdauer der <em>Scoped Value<\/em> g\u00fcltig sein soll:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">RequestContext<\/span> <\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">static<\/span> ScopedValue&lt;User&gt; LOGGED_IN_USER = ScopedValue.newInstance();\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Server<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">serve<\/span><span class=\"hljs-params\">(Request request)<\/span> <\/span>{\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        User loggedInUser = authenticateUser(request);\n        ScopedValue.where(RequestContext.LOGGED_IN_USER, loggedInUser)\n                   .run(() -&gt; restAdapter.processRequest(request));\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-uagb-container uagb-block-8ae4ca2e alignfull uagb-is-root-container\">\n<div class=\"uagb-block-76088612 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">Bis einschlie\u00dflich Java 23 konnten wir alternativ die Convenience-Methode <code>runWhere()<\/code> verwenden und das <code>Runnable<\/code> dieser Methode als dritten Parameter \u00fcbergeben:<br><br><code>ScopedValue.runWhere(<br>&nbsp; &nbsp; RequestContext.LOGGED_IN_USER,<br>&nbsp; &nbsp; loggedInUser,<br>&nbsp; &nbsp; () -&gt; restAdapter.processRequest(request) \/\/ \u27f5 3. Parameter<br>);<\/code><br><br>Diese Variante wurde in <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-24-features\/#Scoped_Values_Fourth_Preview_JEP_487\">Java 24<\/a> entfernt, um die ScopedValue-API komplett \u201efluent\u201c zu gestalten.<\/p><\/div><\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Den <code>loggedInUser<\/code>-Parameter k\u00f6nnen wir dann aus allen Methodensignaturen entfernen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">RestAdapter<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">processRequest<\/span><span class=\"hljs-params\">(Request request)<\/span> <\/span>{ \n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        UUID id = extractId(request);\n        useCase.invoke(id);\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">UseCase<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">invoke<\/span><span class=\"hljs-params\">(UUID id)<\/span> <\/span>{\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        Data data = repository.getData(id);\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\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\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Und dort, wo wir den eingeloggten User ben\u00f6tigen, k\u00f6nnen wir ihn mit <code>ScopedValue.get()<\/code> auslesen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Repository<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> Data <span class=\"hljs-title\">getData<\/span><span class=\"hljs-params\">(UUID id)<\/span> <\/span>{\n        Data data = findById(id);\n        User loggedInUser = RequestContext.LOGGED_IN_USER.get();\n        <span class=\"hljs-keyword\">if<\/span> (loggedInUser.isAdmin()) {\n            enrichDataWithAdminInfos(data);\n        }\n        <span class=\"hljs-keyword\">return<\/span> data;\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\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Das macht den Code deutlich les- und wartbarer, da wir den eingeloggten User nicht mehr von einer Methode zur n\u00e4chsten durchreichen m\u00fcssen, sondern genau dort auf ihn zugreifen k\u00f6nnen, wo wir ihn brauchen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"was-passiert-wenn-kein-wert-gebunden-ist\">Was passiert, wenn kein Wert gebunden ist?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ein Hinweis zu <code>get()<\/code>: Ist der Scoped Value im aktuellen Thread nicht gebunden, wirft <code>get()<\/code> eine <code>NoSuchElementException<\/code>. Wenn nicht sichergestellt ist, dass ein Wert gebunden ist, hast du drei M\u00f6glichkeiten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-comment\">\/\/ Vorab pr\u00fcfen, ob ein Wert gebunden ist:<\/span>\n<span class=\"hljs-keyword\">if<\/span> (RequestContext.LOGGED_IN_USER.isBound()) {\n    User user = RequestContext.LOGGED_IN_USER.get();\n}\n\n<span class=\"hljs-comment\">\/\/ Einen Ersatzwert verwenden, falls kein Wert gebunden ist<\/span>\n<span class=\"hljs-comment\">\/\/ (seit Java 25 darf dieser nicht mehr null sein):<\/span>\nUser user = RequestContext.LOGGED_IN_USER.orElse(User.ANONYMOUS);\n\n<span class=\"hljs-comment\">\/\/ Oder stattdessen eine eigene Exception werfen:<\/span>\nUser user = RequestContext.LOGGED_IN_USER\n            .orElseThrow(() -&gt; <span class=\"hljs-keyword\">new<\/span> IllegalStateException(<span class=\"hljs-string\">\"Kein eingeloggter User\"<\/span>));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Dass <code>orElse(\u2026)<\/code> seit Java 25 kein null mehr akzeptiert, war \u00fcbrigens die einzige \u00c4nderung bei der Finalisierung \u2013 ansonsten wurde die API aus Java 24 unver\u00e4ndert \u00fcbernommen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"aufruf-einer-methode-mit-rueckgabewert\">Aufruf einer Methode mit R\u00fcckgabewert<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn der aufgerufene Code einen R\u00fcckgabewert hat, kannst du nach <code>ScopedValue.where()<\/code> anstelle von <code>run(Runnable op)<\/code> die Methode <code>call(CallableOp op)<\/code> aufrufen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>CallableOp<\/code> ist ein funktionales, generisches Interface, das wie folgt definiert ist:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-meta\">@FunctionalInterface<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">interface<\/span> <span class=\"hljs-title\">CallableOp<\/span>&lt;<span class=\"hljs-title\">T<\/span>, <span class=\"hljs-title\">X<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Throwable<\/span>&gt; <\/span>{\n    <span class=\"hljs-function\">T <span class=\"hljs-title\">call<\/span><span class=\"hljs-params\">()<\/span> <span class=\"hljs-keyword\">throws<\/span> X<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Das Interface enth\u00e4lt neben dem R\u00fcckgabewert auch eine m\u00f6glicherweise geworfene Exception als Typ-Parameter. Somit kann der Compiler erkennen, welche Art von Exception der Aufruf von <code>call(...)<\/code> werfen kann.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn wir also z. B. folgende Methode im Kontext eines <em>Scoped Values<\/em> aufrufen wollen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-function\">Result <span class=\"hljs-title\">doSomethingSmart<\/span><span class=\"hljs-params\">()<\/span> <span class=\"hljs-keyword\">throws<\/span> SpecificException <\/span>{\n    . . .\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Dann erkennt der Compiler, dass auch <code>call()<\/code> nur eine <code>SpecificException<\/code> werfen kann, und wir k\u00f6nnen sie wie folgt abfangen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> {\n    Result result = ScopedValue.where(RequestContext.LOGGED_IN_USER, loggedInUser)\n                               .call(() -&gt; doSomethingSmart());\n} <span class=\"hljs-keyword\">catch<\/span> (SpecificException e) {  <span class=\"hljs-comment\">\/\/ \u27f5 SpecificException abfangen<\/span>\n    . . .\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Und wenn die aufgerufene Methode keine Exception wirft, brauchen wir auch keine abzufangen.<\/p>\n\n\n\n<div class=\"wp-block-uagb-container uagb-block-d0e43dd1 alignfull uagb-is-root-container\">\n<div class=\"uagb-block-677d1316 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">In Java 21 und 22 existierte das Interface <code>CallableOp<\/code> noch nicht. Dort wurde stattdessen ein <code>Callable<\/code> verwendet. Die <code>call()<\/code>-Methode des <code>Callable<\/code>-Interfaces wirft allerdings eine generische Exception:<br><br><code>@FunctionalInterface<br>public interface Callable&lt;V&gt; {<br>&nbsp;   V call() throws Exception;<br>}<\/code><br><br>Und somit musste in Java 21 und 22 beim Aufruf von <code>ScopedValue.call()<\/code> auch immer eine <code>Exception<\/code> abgefangen werden \u2013 selbst wenn die aufgerufene Methode nur eine spezifische oder gar keine Exception werfen konnte.<\/p><\/div><\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-uagb-container uagb-block-bf3b994d alignfull uagb-is-root-container\">\n<div class=\"uagb-block-c060314b uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top \"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\">Bis Java 23 konnten wir alternativ die Convenience-Methode <code>callWhere()<\/code> verwenden. Diese wurde in Java 24 gemeinsam mit <code>runWhere()<\/code> (s. o.) entfernt.<\/p><\/div><\/div>\n<\/div>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"rebinding-von-scoped-values\">Rebinding von Scoped Values<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>ScopedValue<\/code> hat keine <code>set(...)<\/code>-Methode, um den gespeicherten Wert zu \u00e4ndern. Dies ist beabsichtigt, da die Unver\u00e4nderlichkeit eines Wertes komplexen Code deutlich les- und wartbarer macht.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Stattdessen kannst du den Wert f\u00fcr den Aufruf eines begrenzten Code-Abschnitts (z. B. f\u00fcr den Aufruf einer Untermethode) neu binden (\u201eRebinding\u201c auf englisch). D. h., dass f\u00fcr diesen begrenzten Code-Abschnitt ein anderer Wert sichtbar ist ... und sobald dieser Abschnitt beendet wird, wieder der urspr\u00fcngliche.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So k\u00f6nnte unsere <code>RestAdapter<\/code>-Methode z. B. die Informationen \u00fcber den eingeloggten User vor der <code>extractId(<code>...<\/code>)<\/code>-Methode verbergen wollen. Dazu k\u00f6nnen wir erneut <code>ScopedValue.where(...)<\/code> aufrufen und w\u00e4hrend des Aufrufs der Untermethode den eingeloggten User auf <code>null<\/code> setzen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">RestAdapter<\/span> <\/span>{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">processRequest<\/span><span class=\"hljs-params\">(Request request)<\/span> <\/span>{ \n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n        UUID id = ScopedValue.where(RequestContext.LOGGED_IN_USER, <span class=\"hljs-keyword\">null<\/span>)\n                             .call(() -&gt; extractId(request));\n        useCase.invoke(id);\n        <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Hier siehst du auch, wie wir anstelle von <code>run(...)<\/code> die <code>call(...)<\/code>-Methode verwenden und ein <code>Callable<\/code> (also eine Methode mit R\u00fcckgabewert) anstelle eines <code>Runnable<\/code>s \u00fcbergeben.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"vererbung-von-scoped-values\">Vererbung von Scoped Values<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Scoped Values<\/em> werden automatisch an alle Kind-Threads vererbt, die \u00fcber einen <a href=\"\/de\/java\/structured-concurrency-structuredtaskscope\/\">Structured Task Scope<\/a> erzeugt werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mittels <code>StructuredTaskScope<\/code> k\u00f6nnte unser Use Case z. B. parallel zur Repository-Methode noch einen externen Service aufrufen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">UseCase<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">invoke<\/span><span class=\"hljs-params\">(UUID id)<\/span> <span class=\"hljs-keyword\">throws<\/span> InterruptedException <\/span>{\n    <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    <span class=\"hljs-keyword\">try<\/span> (<span class=\"hljs-keyword\">var<\/span> scope = StructuredTaskScope.open()) {\n      Subtask&lt;Data&gt;    dataSubtask    = scope.fork(() -&gt; repository.getData(id));\n      Subtask&lt;ExtData&gt; extDataSubtask = scope.fork(() -&gt; remoteService.getExtData(id));\n \n      scope.join();\n\n      Data    data    = dataSubtask.get();\n      ExtData extData = extDataSubtask.get();\n      <span class=\"hljs-comment\">\/\/ . . .<\/span>\n    }\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">So kann aus den Kind-Threads, die per <code>fork(...)<\/code> erstellt werden, ebenfalls per <code>RequestContext.LOGGED_IN_USER.get()<\/code> auf den eingeloggten User zugegriffen werden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Da der <code>StructuredTaskScope<\/code> erst abgeschlossen ist, wenn alle Kind-Threads beendet sind, passt dieser sehr gut in das Konzept der <em>Scoped Values<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Structured Concurrency<\/em> ist \u2013 anders als <em>Scoped Values<\/em> \u2013 im aktuellen <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-26-features\/\">Java 26<\/a> noch nicht finalisiert und muss per <code>--enable-preview<\/code> aktiviert werden.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"was-ist-der-unterschied-zwischen-scopedvalue-und-threadlocal\">Was ist der Unterschied zwischen ScopedValue und ThreadLocal?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wer die Anforderungen dieser Beispiele bisher mit Thread-Local-Variablen gel\u00f6st hat, wird sich nun vielleicht fragen: Warum brauchen wir <em>Scoped Values<\/em>? Was k\u00f6nnen sie, was Thread Locals nicht k\u00f6nnen?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Scoped Values<\/em> haben folgende Vorteile:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sie sind nur w\u00e4hrend der Laufzeit des an die <code>run(...)<\/code>-Methode \u00fcbergebenen <code>Runnable<\/code>s g\u00fcltig und werden danach (sofern keine weiteren Referenzen auf sie existieren) zur Garbage Collection freigegeben. Ein Thread-Local-Wert hingegen bleibt solange im Speicher, bis entweder der Thread beendet wird (was bei der Verwendung eines Thread-Pools u. U. niemals der Fall ist) oder er explizit mit <code>ThreadLocal.remove()<\/code> gel\u00f6scht wird. Da viele Entwickler:innen vergessen, das zu tun (oder es nicht tun, weil das Programm so komplex ist, dass nicht erkennbar ist, wann ein Thread-Local-Wert nicht mehr ben\u00f6tigt wird), sind Memory Leaks oft die Folge.<\/li>\n\n\n\n<li>Ein <em>Scoped Value<\/em> ist unver\u00e4nderlich \u2013 er kann nur durch das oben erw\u00e4hnte Rebinding f\u00fcr einen neuen Scope neu gesetzt werden. Der Datenfluss l\u00e4uft somit immer in Richtung der Aufrufkette. Das verbessert die Verst\u00e4ndlichkeit und Wartbarkeit des Codes erheblich gegen\u00fcber Thread Locals, die jederzeit durch <code>set()<\/code> ver\u00e4ndert werden k\u00f6nnen.<\/li>\n\n\n\n<li>Die durch <code>StructuredTaskScope<\/code> erzeugten Kind-Threads haben Zugriff auf den <em>Scoped Value<\/em> des Eltern-Threads. Wenn wir hingegen <code>InheritableThreadLocal<\/code> verwenden, wird dessen Wert in jeden Kind-Thread <em>kopiert<\/em>, damit ein Kind-Thread nicht den Thread-Local-Wert des Eltern-Threads ver\u00e4ndern kann. Dies kann den Speicherbedarf erheblich erh\u00f6hen.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Genau wie Thread Locals stehen auch <em>Scoped Values<\/em> sowohl f\u00fcr Plattform-Threads als auch f\u00fcr <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/\">virtuelle Threads<\/a> zur Verf\u00fcgung. Insbesondere bei Tausenden bis Millionen von virtuellen Kind-Threads kann die Speicherersparnis durch den Zugriff auf den <em>Scoped Value<\/em> des Eltern-Threads (anstelle der Erstellung einer Kopie) erheblich sein.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"historie\">Historie<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Scoped Values<\/em> wurden in folgenden JDK Enhancement Proposals definiert:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Java 20: <a href=\"https:\/\/openjdk.org\/jeps\/429\" target=\"_blank\" rel=\"noopener\">JEP 429: Scoped Values (Incubator)<\/a><\/li>\n\n\n\n<li>Java 21: <a href=\"https:\/\/openjdk.org\/jeps\/461\" target=\"_blank\" rel=\"noopener\">JEP 446: Scoped Values (Preview)<\/a><\/li>\n\n\n\n<li>Java 22: <a href=\"https:\/\/openjdk.org\/jeps\/464\" target=\"_blank\" rel=\"noopener\">JEP 464: Scoped Values (Second Preview)<\/a><\/li>\n\n\n\n<li>Java 23: <a href=\"https:\/\/openjdk.org\/jeps\/481\" target=\"_blank\" rel=\"noopener\">JEP 481: Scoped Values (Third Preview)<\/a><\/li>\n\n\n\n<li>Java 24: <a href=\"https:\/\/openjdk.org\/jeps\/487\" target=\"_blank\" rel=\"noopener\">JEP 487: Scoped Values (Fourth Preview)<\/a><\/li>\n\n\n\n<li>Java 25: <a href=\"https:\/\/openjdk.org\/jeps\/506\" target=\"_blank\" rel=\"noopener\">JEP 506: Scoped Values<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"scoped-values-vor-java-25-verwenden\">Scoped Values vor Java 25 verwenden<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Seit <a href=\"https:\/\/www.happycoders.eu\/de\/java\/java-25-features\/#scoped-values-jep-506\">Java 25<\/a> sind Scoped Values final \u2013 du musst nichts weiter tun, um sie zu verwenden.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Falls du sie in Java 21 bis 24 als Preview-Feature einsetzen m\u00f6chtest, musst du Preview-Features explizit freischalten. Dazu rufst du die <code>javac<\/code>- und <code>java<\/code>-Kommandos mit folgenden Optionen auf:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ javac --enable-preview --source &lt;Version&gt; &lt;zu kompilierende .java-Datei&gt;\n$ java --enable-preview &lt;auszuf\u00fchrende .java-Datei oder Klasse&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"fazit\">Fazit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mit <em>Scoped Values<\/em> erhalten wir ein sehr n\u00fctzliches Konstrukt, um einem Thread und ggf. einer Gruppe von Kind-Threads f\u00fcr deren Lebensdauer einen nur lesbaren, Thread-spezifischen Wert zur Verf\u00fcgung zu stellen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Der gr\u00f6\u00dfte Gewinn gegen\u00fcber <code>ThreadLocal<\/code> liegt dabei nicht in der Performance, sondern in der Klarheit: Ein <em>Scoped Value<\/em> ist unver\u00e4nderlich, sein G\u00fcltigkeitsbereich ist direkt am Code ablesbar, und er wird automatisch wieder freigegeben, sobald der <code>run()<\/code>- bzw. <code>call()<\/code>-Block endet. Damit fallen gleich zwei klassische Fehlerquellen von Thread Locals weg \u2013 vergessene <code>remove()<\/code>-Aufrufe und schwer nachvollziehbare Wert\u00e4nderungen quer durch den Aufruf-Stack.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ihre St\u00e4rke spielen Scoped Values besonders im Zusammenspiel mit <a href=\"https:\/\/www.happycoders.eu\/de\/java\/virtual-threads\/\">virtuellen Threads<\/a> und <a href=\"https:\/\/www.happycoders.eu\/de\/java\/structured-concurrency-structuredtaskscope\/\">Structured Concurrency<\/a> aus: Tausende Kind-Threads k\u00f6nnen lesend auf denselben Wert des Eltern-Threads zugreifen, ohne dass dieser kopiert werden muss.<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neuen Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Was ist ein Scoped Value? Wie setzt man ScopedValue ein? Wie werden ScopedValues vererbt? Was ist der Unterschied zwischen ScopedValue und ThreadLocal?<\/p>\n","protected":false},"author":1,"featured_media":34183,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Scoped Values sind seit Java 25 die Alternative zu ThreadLocal. Was sie sind, wie du sie einsetzt und wie sie sich von ThreadLocal unterscheiden.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"ScopedValue,scoped values","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[],"_seopress_pro_schemas_manual":[],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":14234,"_post_count":0,"footnotes":""},"categories":[64],"tags":[220],"class_list":["post-34112","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-nebenlaeufigkeit"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2022\/12\/scoped-values-java.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":0,"uagb_excerpt":"Was ist ein Scoped Value? Wie setzt man ScopedValue ein? Wie werden ScopedValues vererbt? Was ist der Unterschied zwischen ScopedValue und ThreadLocal?","public_identification_id":"228930d0a46b497e9f03c726c12ff175","private_identification_id":"3b546d2f025c45c3863bbd3c2d082b8a","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/34112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/comments?post=34112"}],"version-history":[{"count":36,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/34112\/revisions"}],"predecessor-version":[{"id":56532,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/34112\/revisions\/56532"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34183"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=34112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=34112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=34112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}