<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Nataliia Dziubenko on Medium]]></title>
        <description><![CDATA[Stories by Nataliia Dziubenko on Medium]]></description>
        <link>https://medium.com/@nataliiadziubenko?source=rss-fbe05fbcc7dc------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*0Udf9ncfuUc3fWmgzL0TQA.png</url>
            <title>Stories by Nataliia Dziubenko on Medium</title>
            <link>https://medium.com/@nataliiadziubenko?source=rss-fbe05fbcc7dc------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 01:47:25 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@nataliiadziubenko/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[I won’t let Java confuse you #5: let’s talk lambdas]]></title>
            <link>https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-5-let-s-talk-lambdas-621d9231812b?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/621d9231812b</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[java21]]></category>
            <category><![CDATA[compilers]]></category>
            <category><![CDATA[jvm]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Sun, 30 Jun 2024 13:22:42 GMT</pubDate>
            <atom:updated>2024-06-30T13:22:42.364Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/726/1*mSDxJvgKJi_WLBHTSRRF3Q.png" /></figure><p>Lambdas are interesting structures. What are they exactly? And why can’t we use non-final local variables in lambda bodies?</p><p><em>Welcome back to the Java-unconfusing series! It’s our safe place to take a look at simple pieces of Java code that don’t always behave exactly as we expect. We look under the hood in order to understand why Java does what it does, so we are never confused again.</em></p><h4>Context</h4><p>Years ago, when we were only starting to use the <a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/package-summary.html">Streams API</a> in Java, it took some time to switch the mindset and properly use the new approach.</p><p>For example, in our lambda, we might have tried modifying a variable defined outside the lambda body, which wasn’t possible. But why?</p><h4>What are lambdas</h4><p>Suppose we have a method that accepts a Supplier&lt;Object&gt;:</p><pre>private static void lambdaFun(Supplier&lt;Object&gt; s) {}</pre><p>Supplier is one of the <strong>functional interfaces</strong>. Functional interface is an interface that has one unimplemented method. In this case, it’s a get method, which doesn’t accept any arguments and returns an Object.</p><p>When we are writing a lambda, we are essentially writing an implementation of the specific functional interface expected in the context. So, the lambda like () -&gt; 1, when provided to our lambdaFun method, is considered as an implementation of Supplier&lt;Object&gt;, because that’s what lambdaFun expects.</p><p>Depending on expected type, () -&gt; 1 can be a Supplier&lt;Integer&gt; or even a custom type that we define ourselves. Everything depends on the context.</p><h4>Annoying lambda use-case</h4><p>Let’s take a look at this code:</p><pre>public static void test(int x) {<br>    int y = 1;<br>    lambdaFun(() -&gt; {<br>        y++;<br>        return x + y;<br>    });<br>}</pre><p>In this case, the compiler will give us the following error: Variable used in lambda expression should be final or effectively final. What does that effectively final even mean?</p><h4>What is “effectively final”</h4><p>The Java compiler does a lot of smart things during compilation. It can analyse the use of variables in certain use-cases to determine if they are constant. The variable might not even be marked as final. If it’s defined within a method body, then nothing from outside can modify this variable. Then compiler only needs to check if it’s modified anywhere inside, and if it’s not, the compiler can safely conclude that the variable is effectively final, in other words a constant value.</p><h4>Why is that a problem for lambdas</h4><p>Lambdas don’t allow the use of any variables from outside the lambda body if those variables are not “final or effectively final”. It means they can use variables read-only. Why is that?</p><p>Remember, when we write a lambda body, we’re implementing a functional interface? So, in our Supplier case, we’re saying: this is the body of the get method of that Supplier interface implementation that is magically created “in the air”.</p><p>Let me explain.</p><p>When we compile our code, under the hood a new separate method is created. Say we have this code:</p><pre>public static void test(int x) {<br>    lambdaFun(() -&gt; x);<br>}</pre><p>The () -&gt; x becomes a method body, and in the bytecode this becomes a separate method named lambda$test$0, generated by the compiler, we can see it in the bytecode:</p><pre>private static java.lang.Object lambda$test$0(int);<br>descriptor: (I)Ljava/lang/Object;<br>flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC<br>Code:<br>  stack=1, locals=1, args_size=1<br>     0: iload_0<br>     1: invokestatic  #28                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;<br>     4: areturn<br>  LineNumberTable:<br>    line 7: 0<br>  LocalVariableTable:<br>    Start  Length  Slot  Name   Signature<br>        0       5     0     x   I</pre><p>The synthetic class that actually implements the Supplier interface and uses this method as implementation is generated later, at runtime. And then the actual instance is created. It happens only in the case when the lambda is actually hit, saving up resources when it’s not.</p><p>So, why can’t we normally use outer variables in our lambdas? Simply, because internally lambdas are little methods. Any local variable that they can access, is passed to them (captured) as a method argument. Inside a lambda body, we are viewing a copied value and not an actual variable.</p><h4>Still, why so final?</h4><p>It’s easy to see why the local variable defined outside can’t be modified inside the lambda body. But why does it have to be final, in a sense that even after a lambda definition or even execution it can’t be modified?</p><p>Let’s imagine this limitation doesn’t exist.</p><p>We might want to define a lambda, then try and modify a variable that it uses. The variable value is <em>actually</em> captured at the moment when lambda is <strong>executed</strong>, so all changes between definition and execution should be taken into account. After execution, no changes are visible to lambda, since it has already entered its own stack with its own variable copy.</p><p>This all might look really confusing to a developer. The syntax makes us think that the values are captured at lambda definition, but that’s not true.</p><p>We also need to prevent an expectation, that the changes to a variable after lambda execution are visible in the lambda body. They can’t be.</p><p>It becomes especially important in a multithreaded environment. We might want to execute a lambda in a new Thread, and modify the variable at the moment that looks to us like “after the lambda execution”. But can we be so sure? Did our new Thread already start and execute our lambda when we modified the variable? Which value will actually be captured, the old one, or the amended one?</p><p>Given all of the above, compiler is protecting us from confusions and wrong expectations.</p><h4>What about fields?</h4><p>You might have noticed that there is no problem in reading and modifying the <strong>fields</strong> from our lambdas. Unlike a local variable, which exists with a certain state in a specific method frame, the field is visible to all class members, in all the methods of the class, independent of any frame states. As we remember, lambda body becomes a separate method under the hood. If the field is used in the lambda body, it is not captured as an argument to that method. Instead, the method can read and overwrite that field directly, just as any normal method can do.</p><p>That is easy, when the field and the method are located in the same class. Perhaps, we would like to use a reference to an external method in our lambda instead of generating one in the bytecode? For example, like this:</p><pre>Stream.of(1, 2, 3).forEach(System.out::println);</pre><p>Then indeed no new method is created at compile time, and instead we will have an existing method System.out.println() as our functional interface implementation. However, the syntax wouldn’t allow us to pass any fields to the method reference, which the external method might not even be able to access.</p><h4>Let’s play</h4><p>Digging through <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22">JLS</a> (the Java Language Specification), I stumbled upon a couple of interesting examples of lambda bodies using local variables.</p><p>Let’s have a look.</p><h4>#1</h4><pre>void m1(int x) {<br>    int y = 1;<br>    lambdaFun(() -&gt; x + y);<br>}</pre><p>In this example, both x and y are “effectively final”. They are defined within the m1 method (guaranteed to not be modified from outside). x gets a value when the method m1 is called, and it’s never modified afterward, y is also initialized only once.</p><h4>#2</h4><p>What about this one?</p><pre>void m2(int x) {<br>    int y;<br>    y = 1;<br>    lambdaFun(() -&gt; x + y);<br>}</pre><p>y is only initialized once, so it’s still effectively final. We’re good.</p><h4>#3</h4><pre>void m3(int x) {<br>    int y;<br>    if (x == 2) y = 1;<br>    lambdaFun(() -&gt; x + y);<br>}</pre><p>Variable y is initialized conditionally, in proper terms they call it not definitely assigned. We can’t use an uninitialized variable because then there’s no value for our lambda to capture (to feed it as an argument into a method created under the hood). That won’t compile!</p><h4>#4</h4><pre>void m4(int x) {<br>    int y;<br>    if (x == 2) y = 1; else y = 2;<br>    lambdaFun(() -&gt; x + y);<br>}</pre><p>We do have a conditional assignment to y, but it’s guaranteed that in any condition there will be <em>something</em> (else covers all possible cases). There will be for sure some value that’s going to be assigned to it once and only once. We’re good!</p><h4>#5</h4><pre>void m5(int x) {<br>    int y;<br>    if (x == 2) y = 1;<br>    y = 2;<br>    lambdaFun(() -&gt; x + y);<br>}</pre><p>Here we have a possibility that y gets reassigned, meaning that y is not effectively final. Won’t compile!</p><h4>#6</h4><pre>void m6(int x) {<br>    lambdaFun(() -&gt; x + 1);<br>    x++;<br>}</pre><p>Even though x is modified after our lambda definition, it still means that x is not effectively final. Won’t compile!</p><h4>#7</h4><pre>void m7(int x) {<br>    lambdaFun(() -&gt; x = 1);<br>}</pre><p>Won’t compile either: x is attempted to be modified within lambda body.</p><h4>#8</h4><pre>void m8() {<br>    int y;<br>    lambdaFun(() -&gt; y = 1);<br>}</pre><p>What about this one? y is not having any value, so it can’t be captured by lambda. And then, we are trying to modify it within the lambda body. None of that is going to work…</p><h4>#9</h4><pre>void m9(String[] arr) {<br>    for (String s : arr) {<br>        lambdaFun(() -&gt; s);<br>    }<br>}</pre><p>Here, on each iteration we are creating new instance of String. Each of these instances is definitely assigned a value, and it is guaranteed to happen only once. Everything is alright!</p><h4>#10</h4><pre>void m10(String[] arr) {<br>    for (int i = 0; i &lt; arr.length; i++) {<br>        lambdaFun(() -&gt; arr[i]);<br>    }<br>}</pre><p>Unlike in the previous example, here we are reusing the same variable i and modifying its value by incrementing it on each iteration. Variable i is not effectively final, so this won’t work.</p><h4>#11</h4><pre>void m11(int x) {<br>    int y = 1;<br>    if (x == 2) y = 1;<br>    lambdaFun(() -&gt; x + y);<br>}</pre><p>I know, it looks like we are not changing the value of y here, yet the value is getting overwritten, meaning that the variable is not effectively final. This won’t compile!</p><h4>Conclusion</h4><p>Lambdas are interesting structures. But we can get a feeling of how they are going to behave simply by realizing one thing: lambda body is, or becomes, a separate method. Any local variables that we use in the lambda body are captured as method arguments, so we can access only the copies of the values. Our compiler protects us, so we can’t use non-final local variables in our lambdas.</p><p>Hope this was educative and fun! Here are the related <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22">docs</a>.</p><p>If you liked this little post, take a look at the previous posts from the series:</p><ul><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-4-unreachable-statements-80aaa18a87f0">Unreachable statements</a></li><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-3-widening-13b62ea1091a">Widening</a></li><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-2-expressions-f4dadcfe61e5">Expressions</a></li><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-1-string-concatenation-operator-d9ba389fed72">Concatenation operator</a></li><li><a href="https://medium.com/@nataliiadziubenko/the-hidden-dynamic-life-of-java-12ba9bf95a44">Increment</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=621d9231812b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I won’t let Java confuse you #4: unreachable statements]]></title>
            <link>https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-4-unreachable-statements-80aaa18a87f0?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/80aaa18a87f0</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[compilers]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[code]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Thu, 09 May 2024 19:46:19 GMT</pubDate>
            <atom:updated>2024-05-09T19:46:19.656Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*qrBiBNmAqyKQNnwt1GYQWA.png" /></figure><p>Do you think Java consistently rejects all unreachable code? Well…</p><p><em>Welcome back to the Java-unconfusing series! Usually here we take a look at the pieces of code which may look really innocent, but not work as we expect. Or not compile at all. It’s good to dive into the reasons why it is a certain way, so we can learn more about Java ideology and design decisions. Let’s get unconfused together!</em></p><h4>Let’s talk about unreachable statements</h4><p>There are a number of different use-cases when the code is considered <em>unreachable</em>. The compiler doesn’t accept this code. Examples include statements that follow break or return, or infinite while(true) loops, for example. We have all seen these.</p><p>Let’s take a look at this particular example:</p><pre>int a = 0;<br>while (false) {<br>    a = 10;<br>}</pre><p>The compiler tells us that the loop condition is always false, and that makes the loop body unreachable. Makes sense that it doesn’t compile.</p><p>What about the following example?</p><pre>int a = 0;<br>if (false) {<br>    a = 10;<br>}</pre><p>The condition is always false, which means that the body can never be executed. However, this piece of code is accepted by the compiler! Technically, the Java compiler doesn’t even consider it ‘unreachable’.</p><h4>Why is it so?</h4><p>This choice has been made consciously. When the condition is a constant false value, the compiler doesn’t add the contents of the entire conditional block to the resulting set of the bytecode instructions. This allows developers to define flags such as:</p><pre>static final boolean FEATURE = false;</pre><p>And then use it in a condition.</p><p>Later on, it’s easy to change the value of the FEATURE flag to true, but there’s one important detail to it. If the flag itself and the conditional block are located in different classes, it’s important to recompile the class containing the condition, since the whole new set of instructions might be added to the bytecode.</p><h4>When is it so?</h4><p>Coming back to our while (false) example, such behaviour is only happening when the condition is a <strong>constant</strong> false value.</p><p>So, this would work without any issue:</p><pre>int a = 0;<br>int b = 10;<br>while (b + b &lt; 10) {<br>    a = 1;<br>}</pre><p>While this wouldn’t compile:</p><pre>int a = 0;<br>final int b = 10;<br>while (b + b &lt; 10) {<br>    a = 1;<br>}</pre><p>The reason is that the compiler is performing optimisation called ‘constant folding’. All known (constant) values can be used in order to pre-calculate anything where possible. If the values are constant, the assumptions can be safely made, but not otherwise.</p><p>So, in the example above, the compiler knows that our actual condition is 10 + 10 &lt; 10, and it is false, and it can’t be changed from anywhere else in the code. So it is safe to conclude that the code is invalid.</p><h4>Crazy thoughts</h4><p>Curious minds might wonder: if if (false) {} block contents are not placed into the bytecode at all, does it mean that the compilation of that block is skipped entirely? So any nonsense inside that block would not result in a compile error? The answer is no. The compiler still diligently does its work and reports any compile errors within that block.</p><p>Hope this was educative and fun! Here are the related <a href="https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22">docs</a>.</p><p>If you liked this little post, take a look at the previous posts from the series:</p><ul><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-3-widening-13b62ea1091a">Widening</a></li><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-2-expressions-f4dadcfe61e5">Expressions</a></li><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-1-string-concatenation-operator-d9ba389fed72">Concatenation operator</a></li><li><a href="https://medium.com/@nataliiadziubenko/the-hidden-dynamic-life-of-java-12ba9bf95a44">Increment</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=80aaa18a87f0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I won’t let Java confuse you #3: widening]]></title>
            <link>https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-3-widening-13b62ea1091a?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/13b62ea1091a</guid>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[bytecode]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[compilers]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Wed, 01 May 2024 17:58:22 GMT</pubDate>
            <atom:updated>2024-05-12T13:59:16.361Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*nfQtfyCTS88LyjmfkRiNDA.png" /></figure><p>Welcome to the fourth episode of our Java-unconfusing series, where we look at some basic concepts in Java (in fact, it applies to many other languages too) that result in confusing outcomes in certain cases. When that happens, most likely the code quality could do with some improvements.<br>In any case, it’s good to know what we can expect from Java and never be confused by it.</p><p>Today, I would like to talk about ‘widening’…</p><h4>Example</h4><p>Assume we have two short values and we’d like to calculate their sum. It would make sense to write the following piece of code:</p><pre>short a = 10000 ;<br>short b = 20000 ;<br>short c = a + b;</pre><p>However, this code does not compile. Java compiler considers the result of this expression as integer value instead of short.</p><p>We could, of course, cast the result to short, successfully compile it and get the expected result:</p><pre>short a = 10000 ;<br>short b = 20000 ;<br>short c = (short)(a + b); // c == 30000</pre><h4>Why do we have to cast?</h4><p>If we look at the bytecode of the previous example, we will find a following piece:</p><pre>0: sipush 10000<br>3: istore_1<br>4: sipush 20000<br>7: istore_2<br>8: iload_1<br>9: iload_2<br>10: iadd<br>11: i2s<br>12: istore_3</pre><p>It starts with sipush, and the function of this bytecode operation is literally to push a short onto the stack as an <strong>integer value</strong>.</p><p>The following operation is istore_1, and it already tells us that it stores variable a as integer. Same happens for b.</p><p>All the following operations are simply integer manipulations, including iadd which sums two integer values.</p><p>At the end, because we performed the casting, we find i2s (integer to short) casting operation, but still the final result that is stored in the local variables is again an integer value.</p><h4>But why?</h4><p>What we have observed is called ‘widening primitive conversion’. The short value, which takes two bytes, is put in a bigger ‘box’ of 4 bytes, which is an integer type.</p><p>Why is this happening in this case? There are simply no bytecode instructions which would allow to perform operations directly on short values, so they are converted to integers.</p><h4>OMG, what’s that though?</h4><p>If we write our original code without any casting, but make our variables final, there is no problem compiling that!</p><pre>final short a = 10000 ;<br>final short b = 20000 ;<br>short c = a + b;</pre><p>This behaviour is easy to explain. Let’s take a look at the relevant piece of bytecode:</p><pre> 0: sipush 10000<br> 3: istore_1<br> 4: sipush 20000<br> 7: istore_2<br> 8: sipush 30000<br>11: istore_3</pre><p>As we can see, all values including the resulting sum are considered as constant values. The sum is calculated during compilation and placed directly into the bytecode. This is one of the compiler optimizations called ‘constant folding’.</p><p>In this case, compiler could calculate the sum and see that the resulting value 30000 indeed fits into 2 bytes to be of a short type.</p><p>If we do a slight change to our code so the sum wouldn’t fit into a short type, the compiler immediately starts to complain:</p><pre>final short a = 20000 ;<br>final short b = 20000 ;<br>short c = a + b; // won’t compile, because 40000 doesn’t fit in 2 bytes</pre><p>Note: if we had the same code, but all our values were integer, and the sum didn’t fit into an integer, we would have gotten a warning, but compiler would have accepted it anyway.</p><h4>Cases of widening</h4><p>There are different use-cases of widening primitive conversion. Often it is happening when one of the values in a single operation is of a wider type,<br>so the other value is widened to match.</p><p>Also, short, byte, char and boolean values are always converted to int under the hood. There is simply no means of dealing with these types on the bytecode level.</p><h4>Short doesn’t exist?</h4><p>It’s a good question.</p><p>We have seen from the above examples that short is saved into the local variables as an integer value. So is it just a Java code sugar?</p><p>Using the following code, we can try and figure out, what is the type of our primitive variable:</p><pre>short a = 20000;<br>System.out.println(((Object)a).getClass().getName());</pre><p>The code above outputs java.lang.Short. So did we get something wrong?</p><p>If we look in the bytecode, we will find our answers:</p><pre>0: sipush 20000<br>3: istore_1<br>4: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;<br>7: iload_1<br>8: invokestatic #13 // Method java/lang/Short.valueOf:(S)Ljava/lang/Short;<br>11: invokevirtual #19 // Method java/lang/Object.getClass:()Ljava/lang/Class;<br>14: invokevirtual #23 // Method java/lang/Class.getName:()Ljava/lang/String;<br>17: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/String;)V</pre><p>What is happening here is that we are saving our value as an integer variable. Then we load it onto the stack and use Short::valueOf method to make it short again. Compiler knows, that it’s a short, because we specified it in our code. So it makes sure that our short variables behave as they should. But in the end…</p><p>short is a lie :)</p><p>(yes, and byte as well)</p><p>Hope this was educative and fun!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=13b62ea1091a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I won’t let Java confuse you #2: expressions]]></title>
            <link>https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-2-expressions-f4dadcfe61e5?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/f4dadcfe61e5</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[bytecode]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[compilers]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Mon, 25 Mar 2024 23:03:41 GMT</pubDate>
            <atom:updated>2024-03-25T23:03:41.204Z</atom:updated>
            <content:encoded><![CDATA[<p>Welcome to the third episode of the Java-unconfusing series, where we talk about the things that look innocent, while the results seem confusing. Often that means that the code is not of the best quality. Yet, it’s good to know about such cases and learn how exactly it works.</p><p>Today I’m going to show you a simple numeric expression…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*MQ4012Iu7QebN6xGu0MDOg.png" /></figure><h4>Example</h4><p>Let’s take a look at the following line:</p><pre>System.out.println(1 / 2 + 3.0 * 1 / 2);</pre><p>What do you think is the output?</p><h4>What happened</h4><p>There is nothing interesting happening in the bytecode:</p><pre>0: getstatic     #7  // Field java/lang/System.out:Ljava/io/PrintStream;<br>3: ldc2_w        #13 // double 1.5d<br>6: invokevirtual #15 // Method java/io/PrintStream.println:(D)V<br>9: return</pre><p>The result of the expression is a constant value 1.5d, which means that the expression has been fully pre-calculated (optimised) during compilation.</p><p>But how come it’s 1.5?</p><p>We do expect that the type of the result is double, since we have an explicitly double value 3.0 in the expression.</p><h4>But let’s start with integers</h4><p>If instead of 3.0 we had just 3, we could have expected a result to be an integer.</p><p>So, for integers, we’d have: 1 / 2 + 3 * 1 / 2 = 1.</p><p><strong>Explanation:</strong><br>1 / 2 results in 0, because the rounding to an integer value happens by simply chopping off the remainder, even when it’s 0.5 or greater. <br>So, the expression becomes: 0 + 3 * 1 / 2.<br>Next operation is 3 * 1, because multiplication dominates over addition. We will end up with 3 / 2, which normally equals 1.5, but since it’s an integer value, it becomes 1.</p><h4>Now let’s mix in some doubles</h4><p>Original expression, for reference: 1 / 2 + 3.0 * 1 / 2.<br>This will result in 1.5.</p><p><strong>Explanation:</strong><br>If we follow the appropriate priorities, the first operation we encounter is the leftmost 1 / 2. There are no doubles participating in this operation, so the result is an integer value. Normally, 1 / 2 = 0.5, but with integers it results into 0.</p><p>Now we have: 0 + 3.0 * 1 / 2.<br>The next operation by priority is 3.0 * 1, which will result in a double value 3.0. <br>Our expression transforms into 0 + 3.0 / 2.<br>Next operation is division: 3.0 / 2 = 1.5, the result is double, since we do have a double participant here.<br>The final result is 0 + 1.5 = 1.5.</p><h4>Lessons learned</h4><p>In such confusing expressions with mixed types, it’s important to keep track of the two things:</p><ul><li>What is the next binary operation by priority? Expressions inside the parentheses dominate over the ones outside, the more nested they are, the higher the priority. Multiplication and division dominate over addition and subtraction.</li><li>What are the types of the participants? Double type dominates over integer. String dominates over them all :)</li></ul><p>Remembering that, it’s easy to perform one binary operation at a time (in your head) and keep track of the type and resulting value.</p><p>Hope this was educative and fun!</p><p>If you liked this one, take a look at the previous posts from the series:</p><ul><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-0-increment-bcb91533ce32">Increment</a></li><li><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-1-string-concatenation-operator-d9ba389fed72">String operator </a><a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-1-string-concatenation-operator-d9ba389fed72">+</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f4dadcfe61e5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I won’t let Java confuse you #1: String concatenation operator +]]></title>
            <link>https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-1-string-concatenation-operator-d9ba389fed72?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/d9ba389fed72</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[compilers]]></category>
            <category><![CDATA[bytecode]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Sat, 16 Mar 2024 17:02:57 GMT</pubDate>
            <atom:updated>2024-03-18T08:19:41.382Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*MQ4012Iu7QebN6xGu0MDOg.png" /></figure><p>Welcome to the second episode of this little Java-unconfusing series. Today I would like to talk briefly about String concatenation operator +.</p><p>First, let me share some interesting use-case, then we will take a look under the hood to understand what happened.</p><h4>Example</h4><p>Let’s take a look at the following piece of code:</p><pre>System.out.println(1 + 5 + &quot;text&quot; + 5 + 1);</pre><p>What do you think this code will output?</p><h4>What happened</h4><p>If we look at the bytecode, we will see a very boring piece:</p><pre>0: getstatic     #7    // Field java/lang/System.out:Ljava/io/PrintStream;<br>3: ldc           #13   // String 6text51<br>5: invokevirtual #15   // Method java/io/PrintStream.println:(Ljava/lang/String;)V<br>8: return</pre><p>We see that the String evaluation doesn&#39;t happen at runtime, it has happened at compile time. The whole expression got optimized away, so we&#39;re dealing with a constant value: 6text51.</p><p>But how did this value come to be?</p><p>Going from left to right, only two first operands are taken into account at a time. If none of them is String, and the numeric operation can be performed, it is performed. If any of the two is String, the other operand will also be converted to a String, and they will be concatenated.</p><p>So, in our example, first operation is 1 + 5, which can be evaluated as 6. Next, we will have 6 + &quot;text&quot;, which will result in concatenated String &quot;6text&quot;. Afterwards, all the operations will be resulting in String concatenation, bringing us to the final result: &quot;6text51&quot;.</p><h4>Let&#39;s try something out</h4><p>Let&#39;s try out something strange. As mentioned, the evaluation happens at compile time. What if we force it to happen at the runtime?</p><p>For example, we can create a situation where the exact type of some value is not known at compile time.</p><p>It looks ugly, but bear with me:</p><pre>boolean cond = args[0].contains(&quot;true&quot;);<br>var unknown = cond ? 1 : &quot;text&quot;;<br>System.out.println(unknown + &quot;text&quot; + 5 + 1);</pre><p>Based on what we discussed before, we know that here it doesn’t matter what is the type of the unknown variable, because the second operand is String, so the first two operands will be concatenated.</p><p>This is the relevant piece of bytecode:</p><pre>0: aload_0<br>1: iconst_0<br>2: aaload<br>3: ldc           #7       // String true<br>5: invokevirtual #9       // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z<br>8: istore_1<br>9: iload_1<br>10: ifeq          20<br>13: iconst_1              // this is just a constant integer value, but in the next line we&#39;re going to wrap it into an object<br>14: invokestatic  #15     // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;<br>17: goto          22<br>20: ldc           #21     // String text<br>22: astore_2              // here we&#39;re saving a reference to some object, <br>                          // either a String or Integer, depending what&#39;s on our operand stack at the moment<br>23: getstatic     #23     // Field java/lang/System.out:Ljava/io/PrintStream;<br>26: aload_2               // loading our mystery object onto the stack again<br>                          // the next operation will call a String.valueOf method which will accept the<br>                          // mystery Object as an argument and convert it to a String<br>27: invokestatic  #29     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;<br>                          // finally, the actual operation will result in a String concatenation<br>30: invokedynamic #32,  0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;<br>35: invokevirtual #36     // Method java/io/PrintStream.println:(Ljava/lang/String;)V</pre><p>To summarize the above bytecode: we don&#39;t know at compile time, what’s the type of unknown variable. However, no matter what it is, it&#39;s going to be ultimately converted to a String, because the next operand in our expression is String, so they will be concatenated in any case.</p><p>Now the interesting part. What if we make the second operand non-String?</p><pre>boolean cond = args[0].contains(&quot;true&quot;);<br>var unknown = cond ? 1 : &quot;text&quot;;<br>System.out.println(unknown + 1 + &quot;text&quot; + 5 + 1);</pre><p>Now, the compiler knows that it&#39;s not necessarily a String concatenation. It can be something else depending on the type, but the type of the first operand is unknown... What would you do if you were a compiler?</p><p>The correct answer is: complain :) This simply won&#39;t compile.</p><h4>Lessons learned</h4><p>String concatenation is a very interesting operation, because it leverages a lot of optimizations both at compile time and at runtime.</p><p>Today we saw how the compile time evaluation happens: two operands at a time, from left to right. And if you&#39;re giving your compiler hard time deciding what operation it should perform, it will shout at you.</p><p>Hope this was fun and educative! See you in the next one!</p><p>P.S.: If you liked this one, chances are you’d also like the one about <a href="https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-0-increment-bcb91533ce32">increments</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d9ba389fed72" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I won’t let Java confuse you #0: increment]]></title>
            <link>https://medium.com/@nataliiadziubenko/i-wont-let-java-confuse-you-0-increment-bcb91533ce32?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/bcb91533ce32</guid>
            <category><![CDATA[jdk]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[bytecode]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Wed, 06 Mar 2024 23:53:43 GMT</pubDate>
            <atom:updated>2024-03-06T23:53:43.740Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*MQ4012Iu7QebN6xGu0MDOg.png" /></figure><p>Sometimes the code that seems really clear can turn out to be quite deceiving, even in some really basic concepts. In these situations, it’s good to question whether that code doesn’t smell…</p><p>Either way, it’s interesting to know about the cases where Java can be confusing. So I decided to make the series of little Java surprises.</p><p>Traditionally, I will be peeking under the hood, so we can be efficiently unconfused :)</p><h4>Example</h4><p>Let’s take a look at the following piece of code:</p><pre>int a = 0;<br>a = a++;</pre><p>What is the value of a as result? Did you get it right? It’s 0.</p><h4>What happened?</h4><p>In the bytecode, increment will be performed using the iinc bytecode instruction. The value that we want to increment does not need to be placed onto the operand stack, because iinc modifies the variable directly in the array of local variables.</p><p>Now, still, the post-increment (a++) should work as follows: first use the unmodified value, then increment it.</p><p>Does it mean that it will:</p><ul><li>assign a = a (a is still 0, redundant, but ok)</li><li>increment variable a directly (a should become 1?)</li></ul><p>Not exactly! Let’s take a look at the bytecode, shall we?</p><p>This is the relevant piece:</p><pre>0: iconst_0      // load constant value 0 onto the stack<br>1: istore_1      // save the value from the stack in slot 1<br>2: iload_1       // load from slot 1 to the stack (value = 0)<br>3: iinc     1, 1 // increment the variable in slot 1, it becomes 1 (not the value on the stack, it&#39;s still 0!!)<br>6: istore_1      // save the value from the stack into variable 1 (override variable 1, so it becomes 0)</pre><p>To summarise:</p><ul><li>the value was used in the expression before it was incremented (0)</li><li>the variable was indeed modified afterward (1)</li><li>but then we override it with the result of our expression (0)</li></ul><h4>Ok, another example:</h4><pre>int a = 0;<br>a = a++ + ++a;</pre><p>What is the value of a? Just take a second to process, result will be at the end :)</p><p>Ok, what’s happening:</p><pre>0: iconst_0        // load 0 onto the stack<br>1: istore_1        // store it in slot 1 (value 0)<br> <br>// now our expression is processed from left to right:<br><br>2: iload_1         // load it back onto the stack (value 0),<br>                   // means we will use this a = 0 in the first half of expression, <br>                   // and any increments of this variable in the next lines<br>                   // will affect the variable, but not our stack:<br>3: iinc     1, 1   // post-increment variable in slot 1 (value = 1)<br>6: iinc     1, 1   // this is part of following pre-increment, same variable (value = 2)<br>9: iload_1         // load the variable onto the stack (value = 2)<br>10: iadd           // calculate sum of two top values from the stack (2 + 0 = 2)<br>11: istore_1       // save the resulting value into variable 1</pre><p>This time, the result of post-increment in first part of the expression is not ignored. The expression continues after post-increment, so we are not yet saving anything to the final resulting variable, and we do use the incremented variable again in the expression.</p><p>As result, a becomes 0 + 2 = 2.</p><h4>Lessons learned</h4><p>Unlike post-increment, pre-increment would have modified the value first, and then loaded it onto the stack and used in the expression. So we would have seen a less unexpected result…</p><p><strong>However:</strong></p><ul><li>having increment (or decrement) as part of expressions is <strong>BAD</strong> (makes the code confusing, as you see);</li><li>it is redundant to assign incremented value to itself, because increment modifies the variable directly, so in our example you can do just: a++;.</li></ul><p>Hope this was fun and educative! See you in the next one!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bcb91533ce32" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Hidden Dynamic Life of Java]]></title>
            <link>https://medium.com/@nataliiadziubenko/the-hidden-dynamic-life-of-java-12ba9bf95a44?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/12ba9bf95a44</guid>
            <category><![CDATA[java21]]></category>
            <category><![CDATA[invokedynamic]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[compilers]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Mon, 13 Nov 2023 17:19:50 GMT</pubDate>
            <atom:updated>2023-11-17T23:22:13.901Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This article is an (elaborate) transcript of my talk, ‘</em><a href="https://sessionize.com/s/nataliia-dziubenko/the-hidden-dynamic-life-of-java/76482"><em>The Hidden Dynamic Life of Java</em></a><em>’, presented on </em><a href="https://jfall.nl/"><em>J-Fall</em></a><em> 2023.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/780/1*1lU9KKwfR9EBt4lczhGGYg.png" /></figure><p>It seems like a really smart idea, right? Having the possibility to host many different languages on top of the JVM, which, during compilation, get translated into the standard bytecode format. The JVM doesn’t care what the source language is, as long as the class file is valid.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/796/1*zCvzEGn_si_IIQxxZOT62Q.png" /></figure><p>JVM checks that the format of the class file corresponds to the expected format. Only then will it load and execute the program.</p><p>Designing such system is smart; however, it wasn’t designed with this idea in mind. Initially, the JVM was meant to host only one language — Java.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*ThmwhAtAdh3OlDf1hZ4Q_Q.png" /></figure><p>That means that some of the limitations of Java also constrained the JVM in the same way.</p><h4>Statically vs dynamically typed languages</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*NxDeypW5vA19YxWeGE4qBw.png" /></figure><p>Java is a statically typed language. What does that mean? In statically typed languages, all code gets checked during compile time in order to verify all the types. If the types are incorrect, the compilation will fail, and we won’t even get to the point of invalid bytecode.</p><p>For example, if we have an instance of type String and attempt to invoke a method on this instance that belongs to another type, such as StringBuilder, clearly that won’t be valid. The typing is very strict; even if we were to generate an invalid class file using special tools, the JVM would throw it up before even trying to execute. The advantage of this approach is the short feedback loop and the trust that we have in our code at runtime.</p><p>In dynamically typed languages, types might be not specified in the code at all. Only at runtime will we see if the values we’re actually getting correspond to the types we’re expecting. That can lead to many unpredictable situations at runtime.</p><p>Because Java is a statically typed language, it also implies that the JVM was designed to host a statically typed language. It’s designed to deal with class files where everything is checked in terms of types before the runtime. One might think, is it impossible to build a dynamically typed language on the JVM then?</p><p>As we know, there were a lot of JVM languages emerging, including dynamically typed ones. Here are just a few examples:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/717/1*IWZKameu6C2wlLLyKlph2w.png" /></figure><p>The creators of dynamically typed languages faced challenges in circumventing the limitations. Specifically, they had to address method invocation in situations where the type of an instance that owns the method is unknown at compile time.</p><h4>Possible workarounds</h4><p>Let’s consider this example:</p><pre>def absolute(num):<br>    return num.__abs__()<br><br>print(absolute(-1))<br>print(absolute(&quot;a&quot;))</pre><p>This is a valid piece of Python code. We’re not specifying neither the return type, nor the type of the argument. However, inside the absolute function, we assume, that argument num is numeric, and we call a __abs__ function on it. At runtime, we can call our function with a numeric value, and it will be fine. We can also call it with a str value, and it will fail.</p><p>Imagine you’re a language creator, and you want to make this piece of code runnable on the JVM. How would you work around the limitations?</p><p>One possible solution is to create a language-specific type that covers all possible types you might have. Under the hood, in the bytecode, you would have something like this:</p><pre>public static SuperType abs(SuperType num) {<br>    return num.abs();<br>}<br><br>public static void main(String[] args) {<br>    SuperType result1 = abs(SuperType.of(-2));<br>    SuperType result2 = abs(SuperType.of(&quot;a&quot;));<br>}</pre><p>SuperType becomes your global language-specific type. You accept it as the type of your argument, you return it. In this case, you would need to implement all possible methods that you might want to call on any of your types, and they all should be implemented in your SuperType class. That might be challenging, as it’s hard to know in advance all possible methods you want to have in your types. You’ll also need to consider how to convert Java types into a SuperType, etc.</p><p>This is a possible workaround, but it’s quite an ugly one. Other potential solutions involve reflection or additional interpreters, but they come with their own limitations and are often slow.</p><p>Still, those who were building the dynamically typed languages on JVM, had to use them. Until…</p><h4>Introduction of invokedynamic (indy)</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/954/1*fq9-86c9xYzPVbRMwAlu0g.png" /></figure><p>invokedynamic is a bytecode instruction introduced to support the dynamically typed languages on JVM. Let’s see some other instructions for method invocation and understand how invokedynamic is different.</p><p>In JVM, there are also invokevirtual, invokestatic, invokespecial, and invokeinterface. Let’s take a closer look at two of them that are very commonly used.</p><h4>Invokevirtual</h4><p><strong>invokevirtual </strong>is used when we would like to invoke a method of some instance. Before using this instruction, we should put a reference to the instance that owns this method on top of the operand stack. Afterwards, we have to put all the arguments on top of the operand stack as well, ensuring they all have the correct types. When we use the invokevirtual, we specify the type where the method is located, the method name, the types of the arguments, and return type:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IbMkHo6vV4RW8QgfGesOAA.png" /></figure><p>So, in this case, we put a reference stored in a static field System.out onto the stack. Its type is PrintStream. Afterward, we place the constant String value on top of the stack, which will be the argument that the method accepts. When we use invokevitual, we specify that the method’s name is println, the method is located inside PrintStream, it accepts a single argument of type String, and returns void. It’s not possible to use invokevirtual without this diligent specification of all these details, so for dynamically typed languages it’s not usable.</p><h4>Invokestatic</h4><p><strong>invokestatic </strong>does a similar job. The only difference is that we’re invoking a static method, so there is no instance that owns it. That means we don’t need to place any reference of the owner instance onto the stack. Still, we have to place all the arguments there:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xK1IbdF98JQ1dNSUgkjw9w.png" /></figure><p>For theinvokestatic instruction, we also need to specify the type where the method is located, along with the method name and all the types. In this case, the method belongs to theString type, its name is valueOf, and it accepts an int while returning a String.</p><h4>How is indy different?</h4><p>As in the previous examples, the invokedynamic instruction also requires you to provide the arguments onto the stack. However, it doesn’t require you to specify either where the method is located or its name. We are only specifying that eventually, we would like to call a method that accepts an int and returns a String. We are also specifying some method name makeConcatWithConstants, but in this case, it’s arbitrary and won’t play any role.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-3v3w8-ZbN4OD0gyJiT4SQ.png" /></figure><p>The crucial element is the reference #0, which points to another section in the bytecode called BootstrapMethods. A bootstrap method is a method that makes a decision at runtime about which target method we would like to invoke. This means that at compile time, we don’t even know where that method is located and how it’s called, but the bytecode is still valid!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/611/1*pjPbUWk1S6iolOB0ev5S_w.png" /></figure><p>When the JVM executes the bytecode and encounters the invokedynamic instruction, it invokes the bootstrap method. The bootstrap method performs some logic (which can include generating synthetic code, among other things), and ultimately, it looks up a MethodHandle for the method that needs to be invoked. A MethodHandle is a mechanism, similar to reflection but faster, that provides a direct reference to the method. The JVM then links that target method handle to the specific invokedynamic instruction and invokes the target method.</p><p>When the JVM encounters this particular invokedynamic instruction again, if nothing has changed, it directly invokes the linked target method. The method handle lookup doesn’t happen again in this case.</p><h4>Alright, back to Java</h4><p>This provides a lot of possibilities for creators of dynamically typed languages, but I promised to talk about Java.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/788/1*F3W6PzDiVRl7IWwUMuqzqA.png" /></figure><p>It turns out that invokedynamic is often used by the Java compiler, so there are more and more use-cases where we can find it in the bytecode generated by javac.</p><p>Let’s take a look at some of them.</p><h4>String concatenation</h4><p>In Java, invokedynamic (indy) is used for some cases of String concatenation. Of course, when we&#39;re concatenating constant values, the compiler optimizes the entire concatenation away. However, if we&#39;re dealing with non-final variables, we will find invokedynamic in the bytecode.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G3sGAdvYWvfUR-9wcY44Qg.png" /></figure><p>In the example above, we’re concatenating two String variables. In the bytecode, we place both references to them onto the operand stack. Then, we use indy, where we say that we want to find a target method at runtime, and that method will accept two Strings and return a String.</p><p>In the BootstrapMethods section, we use the StringConcatFactory::makeConcatWithConstants method. It accepts many arguments, most are automatically filled in by the JVM. We can also provide some arguments through Method arguments. In this case, we’re providing a “recipe”, which is kind of a template with placeholders for parameters. This way, we provide information to the Bootstrap Method on how exactly we’d like to concatenate the elements.</p><p>What does the Bootstrap Method do? This is some of its logic:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0T6LaL0Xg8FQOUtgdGRIGQ.png" /></figure><p>It turns out that both unary and binary concatenations can go through a faster implementation than other cases. We have two elements, both being parameters and non-primitive and non-null values, so we lookup a simpleConcat method for them. This method performs basic byte array manipulations, similar to how StringBuilders work.</p><p>What did indy give us in this case? The ability to make a decision at runtime: determine which logic is more performant for this use-case and eliminate unnecessary logic at all.</p><h4>Pattern matching for switch</h4><p>In the newest Pattern Matching for Switch, we’re also using the invokedynamic! We now have the ability to switch over different types:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ISebhIZsyES6CQIH0YYQwA.png" /></figure><p>Here, we have String and Integer types, and there could be more. We can also use guard conditions, in which case the types might be repeated. But what is happening under the hood?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*V8NKppR-LV2gtwdgC8-DQw.png" /></figure><p>The task of the target method here is to return an integer. That integer value helps the next instruction to find the location in the bytecode where to jump and execute some block of code. That’s it.</p><p>We provide the arguments to the bootstrap method, which is simply a list of all types we’re switching over. For each type, the bootstrap method looks up a method handle for a method that does type checking for that particular type, and these method handles are then combined in a chain and encapsulated into a final MethodHandle. When invoked at runtime, this final MethodHandle executes all the checks for all the types, and depending on these checks, it calculates the integer value to return.</p><p>In summary, we have a dynamic decision-making logic that is executed at runtime.</p><h4>Lambdas</h4><p>The most exciting part where indy is used in Java is with Lambdas.</p><p>When we define a lambda body, we’re essentially implementing a functional interface (an interface with a single abstract method). Indy allows us to have a synthetic class that implements that method with whatever implementation we provide as the lambda body. Then, we can get instances of this implementation whenever needed, and all of this happens at runtime! No extra classes are generated during compilation.</p><p>Let’s take a look at this example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cK7KqIomF9cD-hFoypXTrw.png" /></figure><p>Here, our functional interface is Consumer. We use invokedynamic, specifying that we want the accept method to be implemented with the code from the lambda body.</p><p>At runtime, the bootstrap method creates a synthetic class that implements the accept method of Consumer. The target method handle that the bootstrap method gives us back is simply a factory, which returns an instance of this Consumer implementation whenever we hit this invokedynamic instruction. Afterwards, we can provide this instance to the forEach method.</p><p>In this case, we specify that we want the accept method to do what System.out::println does, so we simply provide a reference to that method as an argument. Alternatively, we could use a custom block of code. In that case, during compilation, that block of code would be placed in a separate method, and we would provide a reference to that method.</p><p>In summary, indy allows us to generate code only in the case when the lambda is actually hit and only once. Moreover, we&#39;re not polluting our bytecode with all the extra classes because all of this is taken care of during runtime.</p><h4>What about AOT?</h4><p>As we know, AOT compilation doesn’t like any dynamic behavior because all possible invocations should be known ahead of time.</p><p>Consider GraalVM native image, for instance. If there’s anything dynamic, such as reflection, we also have to provide a configuration where we specify all the possible methods that could be called through reflection at runtime.</p><p>How does the invokedynamic work then?</p><p>Well, anything that javac (as well as the Kotlin compiler) places in the bytecode is supported by GraalVM out of the box. These cases are known, and there’s a limited amount of them, so GraalVM simply takes them into account inside the logic of native image creation.</p><p>If you’re building a new compiler, you probably want to establish some agreements about such support. If you’re manipulating the bytecode, be careful (and not too creative) when playing with the invokedynamic instruction; otherwise, the produced bytecode might fail inside the native image.</p><h4>Final words</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*efVhRKyFOZMpPJz4lgWJUw.png" /></figure><p>After playing with invokedynamic for several months… I have finally stopped asking myself ‘why’. Why is it good for Java? What are the benefits?</p><p>Indy helps us reduce the <strong>complexity</strong> of the bytecode. We save <strong>space</strong> by not polluting our bytecode with all the things that are not even related to our program, such as all the language logic. The logic becomes more and more complicated with the newer versions of Java, so it’s good to have it <strong>abstracted away</strong>.</p><p>The implementation of some language features can improve from version to version, and <strong>we don’t even need to change the bytecode</strong> (rebuild the project) to benefit from them. We won’t even notice that something has changed, but the program might become more <strong>performant</strong>.</p><p>Believe me, the implementation of language features does change. For pattern matching, I looked at how it worked in the Java 21 Early Access version, and then I looked again when Java 21 was actually released. The implementation was completely different… and yet, the bytecode remained the same.</p><p>Can there be any downsides? Of course. The <strong>predictability</strong> of our program might decrease without us making any changes. Perhaps the previous implementation of String concatenation was less performant but gained performance by taking up more space? By putting more String instances onto the heap? That might be the case, as the previous implementation of String concatenation used StringBuilders, and now it’s different.</p><p>Things might change for better or worse, but, of course, all these changes are intended to benefit us in future versions.</p><h4><strong>Resources</strong></h4><p>I was heavily relying on this article when I spoke about dynamically typed languages on JVM. Take a look if you’re interested to dig deeper into the topic:</p><p><a href="https://www.oracle.com/technical-resources/articles/javase/dyntypelang.html">New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=12ba9bf95a44" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Java compiler-decompiler ping-pong]]></title>
            <link>https://medium.com/@nataliiadziubenko/java-compiler-decompiler-ping-pong-8190a590a309?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/8190a590a309</guid>
            <category><![CDATA[compilers]]></category>
            <category><![CDATA[decompile]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[bytecode]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Tue, 31 Oct 2023 21:43:20 GMT</pubDate>
            <atom:updated>2023-10-31T21:43:20.670Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*bXqi3lR-W7CWPk0BWL5j-A.png" /></figure><p>This small episode related to Java compilation seemed interesting and a bit funny to me, so I’m sharing it here. Hope you enjoy it too 😊</p><p>I was working on a (pet) tool for editing class files in the format of Java code. For that, I was using the <a href="https://github.com/mstrobel/procyon">Procyon</a> decompiler and the <a href="https://docs.oracle.com/javase/8/docs/api/javax/tools/JavaCompiler.html">Java Compiler API</a>. So, simply, I needed to “translate” the code back and forth, from the JVM bytecode to Java, and then back to the bytecode.</p><p>It was also important for me to ensure that I compiled the code using the exact Java version with which it was originally compiled. I used <a href="https://asm.ow2.io/documentation.html">ASM</a> to retrieve the Java version from the class file, so then I could provide it to the compiler.</p><p>When I started testing it with some Java code, it went fine with my first (somewhat bigger) example. However, when I started trying out different Java versions, suddenly my method got empty in the final result (bytecode — &gt; decompiled to Java — &gt; compiled to bytecode). I thought that I broke it by using a different Java version, but actually the problem had a completely different origin.</p><p>Example Java code that I used for testing:</p><pre>public class Main {<br>   public static void main(String[] args) {<br>       int num = 42;<br>       String test = &quot;I have &quot; + num + &quot; cows!&quot;;<br>   }<br>}</pre><p>When this code is compiled, it utilizes the invokedynamic instruction in the bytecode for this case of String concatenation. Usually, when you view class files in IntelliJ IDEA, they are shown decompiled with <a href="https://github.com/fesh0r/fernflower">Fernflower</a>:</p><pre>public class Main {<br>   public Main() {<br>   }<br><br><br>   public static void main(String[] args) {<br>       int num = 42;<br>       String test = &quot;I have &quot; + num + &quot; cows!&quot;;<br>   }<br>}</pre><p>Looks good.</p><p>In my project, this was decompiled using Procyon and looked slightly differently:</p><pre>public class Main<br>{<br>   public static void main(final String[] args) {<br>       final int num = 42;<br>       final String test = &quot;I have &quot; + num + &quot; cows!&quot;;<br>   }<br>}</pre><p>And then, if the above Java code is compiled, the Code section in the bytecode for the main method is empty! Decompiled again, it would look like this:</p><pre>public class Main {<br>   public Main() {<br>   }<br><br><br>   public static void main(String[] var0) {<br>   }<br>}</pre><p>I understood that the variables are optimized away because they are not used. So I added a “blackhole” for them, which was represented by System.out::println:</p><pre>public static void main(String[] args) {<br>   int num = 42;<br>   String test = &quot;I have &quot; + num + &quot; cows!&quot;;<br>   System.out.println(test);<br>}</pre><p>Eventual result from my project (decompiled again):</p><pre>public class Main {<br>   public Main() {<br>   }<br><br><br>   public static void main(String[] var0) {<br>       System.out.println(&quot;I have 42 cows!&quot;);<br>   }<br>}</pre><p>I was like, no invokedynamic? Just a boring constant value? What happened? The thing is, Procyon added the final keyword for my variables, which tells the compiler that they have fully constant values in the end:</p><pre>final int num = 42;</pre><p>For the case of String concatenation that involves only constant (final) values, there will be no invokedynamic whatsoever. It will simply be a constant value.</p><p>Two different decompilers produce results that are not incorrect, but vary a bit. Procyon was smart enough to analyse the code and figure out that the variables were <em>effectively</em> final, so it marked them as final(I’d argue if it really had to).</p><p>To be honest, I had some Google Translate vibes (try translating between two languages back and forth for several times).</p><p>It seems, if my tool ever comes to life, it will be fun to use it 😛</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8190a590a309" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Java Invokedynamic: Bootstrapping an Alternative Method]]></title>
            <link>https://medium.com/better-programming/java-invokedynamic-bootstrapping-an-alternative-method-11b788e99579?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/11b788e99579</guid>
            <category><![CDATA[jdk]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[java21]]></category>
            <category><![CDATA[compilers]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Mon, 18 Sep 2023 20:00:28 GMT</pubDate>
            <atom:updated>2024-03-18T15:14:21.778Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/744/1*iTbdCpVn0gRUn_j2T2OQwA.png" /><figcaption>Made by author</figcaption></figure><p>This experiment intends to demonstrate the power of the invokedynamic instruction in JVM. This instruction is used for different pieces of Java functionality these days, such as switch statements, lambdas, and many cases of String concatenation.</p><p>The idea is that, in the bytecode of our compiled class, invokedynamic points to some specific Bootstrap Method, which at runtime can choose a target method to be invoked. This way, we can have compact bytecode without even knowing, for example, which method concatenates Strings for us. If newer Java versions improve performance or add more alternative methods to choose from, we won’t need to do anything to benefit from them.</p><h4>Redefining the Bootstrap method</h4><p>Can we redefine the Bootstrap Method and invoke another target method at runtime? My experiment proves that it’s possible, although clearly, we shouldn’t ever want to do this :). It’s not intended for any real-life situations.</p><h4>The case of String concatenation</h4><p>As I mentioned, String concatenation is widely leveraged by invokedynamic. Depending on the number of parts to concatenate and their types, the behaviour can differ.</p><p>Let’s consider the following example:</p><pre>public class Test {<br>    public static void main(String[] args) {<br>        String test = &quot;something&quot;;<br>        System.out.println(&quot;something lalala something else &quot; + test);<br>    }<br>}</pre><p>When we compile this class and check the bytecode, we see the invokedynamic instruction in the Code section of our main method:</p><pre>...<br><br>0: ldc           #7       // String something<br>2: astore_1<br>3: getstatic     #9       // Field java/lang/System.out:Ljava/io/PrintStream;<br>6: aload_1<br>7: invokedynamic #15,  0  // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;<br>12: invokevirtual #19     // Method java/io/PrintStream.println:(Ljava/lang/String;)V<br>15: return<br><br>...<br><br>BootstrapMethods:<br>  0: #36 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;<br>    Method arguments:<br>      #34 something lalala something else \u0001<br>...</pre><p>In the BootstrapMethods section, we see which method exactly is responsible for determining the dynamic behaviour: StringConcatFactory.makeConcatWithConstants.</p><p>Without going into too much detail, the functionality triggered by this method involves checking some parameters and their types. It then looks up the MethodHandle of a specific method and wraps it in a CallSite instance. Then, the found method is invoked via the JVM mechanisms.</p><p>StringConcatFactory is all about this bootstrapping logic. Most of the target methods it finds in the end are in StringConcatHelper class.</p><p>For example, this is the body of method simpleConcat, which will be called for our specific use case (for concatenating a constant String and a variable of non-primitive type):</p><pre>    private static MethodHandle simpleConcat() {<br>        MethodHandle mh = SIMPLE_CONCAT;<br>        if (mh == null) {<br>            MethodHandle simpleConcat = JLA.stringConcatHelper(&quot;simpleConcat&quot;,<br>                    methodType(String.class, Object.class, Object.class));<br>            SIMPLE_CONCAT = mh = simpleConcat.rebind();<br>        }<br>        return mh;<br>    }</pre><p>It looks up the method StringConcatHelper::simpleConcat, which accepts two Object arguments, and returns a String. At the moment when the target method is invoked, there will be two Objects sitting on top of our operand stack. We can also cheat a bit because we know that, in our case, these Objects will be Strings.</p><h4>How do we use this knowledge?</h4><p>Can we override the body of this method and look up some other MethodHandle? Of course we can! But we should keep in mind that the signatures should match. Or, if they don’t match, we can manually inject some extra arguments.</p><p>I thought it would be fun to look up the String::replaceAll method. Unlike the original method that is called, it’s not a static method. Both of our Strings will come in as method arguments for the original method. However, for replaceAll, the first String will be the owner Object reference, and the second one will come in as the first method argument (replace what). We are missing the second argument (replacement), but we can inject this one ourselves.</p><h4>Looking up some other MethodHandle</h4><p>This code does the job:</p><pre>MethodHandles.Lookup lookup = MethodHandles.lookup();<br>MethodType mt = MethodType.methodType(String.class, String.class, String.class);<br>MethodHandle mh = lookup.findVirtual(String.class, &quot;replaceAll&quot;, mt);<br>return MethodHandles.insertArguments(mh, 2, &quot;^_^&quot;);</pre><p>We can test what this does with a simple example:</p><pre>mh.invoke(&quot;rrrrr aaa fffff&quot;, &quot;aaa&quot;);</pre><p>As a result, it will replace all “aaa” in “rrrrr aaa fffff” with cute smileys “^_^” , so we will end up with “rrrrr ^_^ fffff”.</p><h4>The bytecode</h4><p>To override the method in StringConcatFactory class, we will need to manipulate the bytecode. The above code that we want to use as the new body for simpleConcat method results in this bytecode:</p><pre>0: invokestatic  #35  // Method java/lang/invoke/MethodHandles.lookup:()Ljava/lang/invoke/MethodHandles$Lookup;<br>3: astore_0<br>4: ldc           #41  // class java/lang/String<br>6: ldc           #41  // class java/lang/String<br>8: iconst_1<br>9: anewarray     #43  // class java/lang/Class<br>12: dup<br>13: iconst_0<br>14: ldc           #41 // class java/lang/String<br>16: aastore<br>17: invokestatic  #45 // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;<br>20: astore_1<br>21: aload_0<br>22: ldc           #41 // class java/lang/String<br>24: ldc           #51 // String replaceAll<br>26: aload_1<br>27: invokevirtual #53 // Method java/lang/invoke/MethodHandles$Lookup.findVirtual:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;<br>30: astore_2<br>31: aload_2<br>32: iconst_2<br>33: iconst_1<br>34: anewarray     #2  // class java/lang/Object<br>37: dup<br>38: iconst_0<br>39: ldc           #59 // String  ^_^<br>41: aastore<br>42: invokestatic  #61 // Method java/lang/invoke/MethodHandles.insertArguments:(Ljava/lang/invoke/MethodHandle;I[Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;<br>45: areturn<br>46: astore_0<br>47: aconst_null<br>48: areturn</pre><h4>The plan</h4><p>To achieve my goal, I need to:</p><ul><li>Create a Java Agent that redefines the Bootstrap Method. When running a test program, we can simply specify a javaagent that we want to hook into the JVM. The Java Agent then does its dirty job before the invocation of the main method of our test program.</li><li>Java 21 has a beautiful (internal) <a href="https://openjdk.org/jeps/8280389">Class-File API </a>for manipulating bytecode. Pretty cool thing, by the way! I’m looking forward to it coming out. We will try and use it to override a method body.</li></ul><h4>Simplest Java agent</h4><p>Java Agents and Instrumentation give a lot of possibilities, such as transformation of classes when they are loaded, access to ClassLoader information and many more.</p><p>We will make a very simple Java Agent. We will create a class that implements this method:</p><pre>public static void premain(String agentArguments, Instrumentation instrumentation) {}</pre><p>This method, as the name suggests, is triggered before the main method of our test program. Once the implementation is done, we will specify some settings in the manifest file and create a jar package. Finally, we can use the jar package as a javaagent when we run the JVM.</p><p>Alternatively, we could have created a class transformer and added it via Instrumentation:</p><pre>instrumentation.addTransformer(new BootstrapStringConcatTransformer(), true);</pre><p>Then, our class transformer BootstrapStringConcatTransformer would be triggered for all classes that get loaded. However, our target class is not loaded before runtime because, before runtime, the JVM doesn’t even know what invokedynamic will need! So, we will need to load the class of interest ourselves and then redefine it.</p><h4>Class-File API</h4><p>There aren’t a lot of docs for the Class-File API yet. This API is not exposed to the world yet, but it’s interesting to try it out! <a href="https://openjdk.org/jeps/8280389">This</a> is the only good example of usage that I found. To be able to use it, we have to add the --add-exports option to use the closed jdk.internal.* packages.</p><p>After playing with it a bit, I got to the following code, which is not polished, but it works:</p><pre>public static void premain(String agentArguments, Instrumentation instrumentation) throws ClassNotFoundException, IOException, UnmodifiableClassException, URISyntaxException {<br>    Class clazz = Class.forName(&quot;java.lang.invoke.StringConcatFactory&quot;); // here we actually load the class<br>    ClassModel classModel = Classfile.parse(Path.of(clazz.getResource(&quot;StringConcatFactory.class&quot;).toURI()));<br><br>    var bytes =  Classfile.build(classModel.thisClass().asSymbol(), classBuilder -&gt; {<br>        for (ClassElement classElement : classModel) {<br>            if (classElement instanceof MethodModel methodModel &amp;&amp;<br>                    methodModel.methodName().equalsString(&quot;simpleConcat&quot;)) {<br>                classBuilder.withMethod(methodModel.methodName(), methodModel.methodType(),<br>                        methodModel.flags().flagsMask(), methodBuilder -&gt; {<br>                            methodBuilder.withCode(codeBuilder -&gt; {<br>                                var stringClassEntry = classBuilder.constantPool().classEntry(classBuilder.constantPool().utf8Entry(&quot;java/lang/String&quot;));<br>                                // using the beautiful API below, I pretty much wrote the bytecode above 1:1 to the code<br>                                codeBuilder<br>                                        .invokestatic(ClassDesc.of(&quot;java.lang.invoke.MethodHandles&quot;),<br>                                                &quot;lookup&quot;, MethodTypeDesc.ofDescriptor(&quot;()Ljava/lang/invoke/MethodHandles$Lookup;&quot;))<br>                                        .astore(0)<br>                                        .ldc(stringClassEntry)<br>                                        .ldc(stringClassEntry)<br>                                        .iconst_1()<br>                                        .anewarray(classBuilder.constantPool().classEntry(classBuilder.constantPool().utf8Entry(&quot;java/lang/Class&quot;)))<br>                                        .dup()<br>                                        .iconst_0()<br>                                        .ldc(stringClassEntry)<br>                                        .aastore()<br>                                        .invokestatic(ClassDesc.of(&quot;java.lang.invoke.MethodType&quot;),<br>                                                &quot;methodType&quot;, MethodTypeDesc.ofDescriptor(&quot;(Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;&quot;))<br>                                        .astore(1)<br>                                        .aload(0)<br>                                        .ldc(stringClassEntry)<br>                                        .ldc(classBuilder.constantPool().stringEntry(&quot;replaceAll&quot;))<br>                                        .aload(1)<br>                                        .invokevirtual(ClassDesc.ofDescriptor(&quot;Ljava/lang/invoke/MethodHandles$Lookup;&quot;), &quot;findVirtual&quot;,<br>                                                MethodTypeDesc.ofDescriptor(&quot;(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;&quot;))<br>                                        .astore(2)<br>                                        .aload(2)<br>                                        .iconst_2()<br>                                        .iconst_1()<br>                                        .anewarray(classBuilder.constantPool().classEntry(classBuilder.constantPool().utf8Entry(&quot;java/lang/Object&quot;)))<br>                                        .dup()<br>                                        .iconst_0()<br>                                        .ldc(classBuilder.constantPool().stringEntry(&quot;^_^&quot;))<br>                                        .aastore()<br>                                        .invokestatic(ClassDesc.of(&quot;java.lang.invoke.MethodHandles&quot;),<br>                                                &quot;insertArguments&quot;, MethodTypeDesc.ofDescriptor(&quot;(Ljava/lang/invoke/MethodHandle;I[Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;&quot;))<br>                                        .areturn()<br>                                        .astore(0)<br>                                        .aconst_null()<br>                                        .areturn();<br>                            });<br>                        });<br>            }<br>            else classBuilder.with(classElement);<br>        }<br>    });<br>    // this is useful for debugging the result as the decompiled code:<br>    Files.write(new File(&quot;lalala.class&quot;).toPath(), bytes);<br>    instrumentation.redefineClasses(new ClassDefinition(clazz, bytes));<br>}</pre><h4>Packaging the agent</h4><p>I compiled the Java Agent code with these options:</p><pre>javac --add-exports java.base/jdk.internal=ALL-UNNAMED --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED --add-exports java.base/jdk.internal.classfile.instruction=ALL-UNNAMED --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED smthelusive/Main.java</pre><p>Then, I created the manifest with the following settings:</p><pre>Manifest-Version: 1.0<br>Premain-Class: smthelusive.Main<br>Can-Retransform-Classes: true<br>Can-Redefine-Classes: true</pre><p>And packaged a jar:</p><pre>jar cfm fakebootstrapagent.jar META-INF/MANIFEST.MF smthelusive/</pre><h4>Testing the result</h4><p>For reference, this is our test program again:</p><pre>public class Test {<br>    public static void main(String[] args) {<br>        String test = &quot;something&quot;;<br>        System.out.println(&quot;something lalala something else &quot; + test);<br>    }<br>}</pre><p>Let’s test our program without javaagent using the java Test command. This is the result:</p><pre>something lalala something else something</pre><p>Now, let’s attach our javaagent (unfortunately, we need to keep all the package opening options for it to work):</p><pre>java --add-exports java.base/jdk.internal=ALL-UNNAMED --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED --add-exports java.base/jdk.internal.classfile.instruction=ALL-UNNAMED --add-exports java.base/jdk.internal.classfile.constantpool=ALL-UNNAMED <strong>-javaagent:fakebootstrapagent.jar</strong> Test</pre><p>Here’s the result:</p><pre>^_^ lalala ^_^ else </pre><p>The concatenation is no longer concatenating 😛.</p><h3>Final Thoughts</h3><p>Would have been fun to replace the target method with some custom method, right? Unfortunately, that didn’t work out for me. I tried providing my custom method packaged in a jar through Instrumentation (yes, it’s also possible) so it’s available for bootstrap ClassLoader.</p><p>This code would be accessible by any code in my Test program. However, JDK internal code isn’t allowed to access the code I provide. If you know the options to “make it allowed,” please let me know.</p><p>I have also tried to add an extra method in the StringConcatHelper class, but it’s impossible to add any methods or change the signatures of existing ones. The reason is that the class is already loaded now, and the class data is stored in appropriate memory slots.</p><p>You may be wondering, why did I try this in the first place? Because, why not? Thank you for your attention, and stay tuned for the next JVM torturing episodes!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=11b788e99579" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/java-invokedynamic-bootstrapping-an-alternative-method-11b788e99579">Java Invokedynamic: Bootstrapping an Alternative Method</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Java 21: So How Should We Construct Strings Now?]]></title>
            <link>https://medium.com/better-programming/java-21-so-how-should-we-construct-strings-now-772752607d43?source=rss-fbe05fbcc7dc------2</link>
            <guid isPermaLink="false">https://medium.com/p/772752607d43</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[jvm]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Nataliia Dziubenko]]></dc:creator>
            <pubDate>Fri, 18 Aug 2023 08:36:58 GMT</pubDate>
            <atom:updated>2024-04-15T23:30:37.528Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*VANSz4lBqGe1sxOqFRa7Og.png" /><figcaption>Image by author</figcaption></figure><p><em>Note: if you can’t fully view this article, you can read it </em><a href="https://nataliiadziubenko.com/2023/08/18/so-how-should-we-construct-strings.html"><em>in my blog</em></a><em>.</em></p><p>Java 21 brings in a lot of cool features, and one of them is the preview of String Templates<strong>*</strong>. While it serves more purposes than just classic String interpolation, for us Java developers, it’s yet another way to concatenate Strings in a “proper” way.</p><p>What is <em>proper,</em> though? I poked around the bytecode and learned some interesting and surprising things about different String concatenation and interpolation techniques in modern Java.</p><p>I’ve also compared it with the Kotlin way (under the hood) 😏.</p><p>But let’s begin with Java.</p><h4>+ operator</h4><p>We’ve always known that using a + operator is bad practice since Strings are immutable, and under the hood, a new String gets instantiated for every part we concatenate. However, as they say in Dutch, “meten is weten,” which means “measuring is knowing.” Let’s see what is <em>really</em> happening inside:</p><pre>// example #1:<br>String example1 = &quot;some String &quot; + 42;<br><br>// example #2:<br>int someInt = 42;<br>String example2 = &quot;some String &quot; + someInt + &quot; other String &quot; + someInt;<br><br>// example #3:<br>String example3 = &quot;&quot;;<br>for (int i = 0; i &lt; 10; i++) {<br>    example3 += someInt;<br>}</pre><p>In the bytecode, example #1 translates into a single String allocation. Java compiler is smart enough to see that the magic number is constant, so it is loaded as part of the String onto the operand stack:</p><pre>0: ldc     #7  // String <strong>some String42</strong></pre><p>Of course, we don’t want to use the magic values, so let’s see what happens with the variables.</p><p>In example #2, the Java compiler can’t perform the same optimisation when we’re using a variable, but it does some advanced stuff with invokedynamic:</p><pre>0: bipush        42<br>2: istore_1<br>3: iload_1<br>4: iload_1<br>5: invokedynamic #7,  0  // InvokeDynamic #0:makeConcatWithConstants:(II)Ljava/lang/String;<br><br>...<br><br>BootstrapMethods:<br>  0: #22 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;<br>    Method arguments:<br>      #23 some String \u0001 other String \u0001</pre><p>This instruction allows bootstrapping the method at runtime that needs to be called for concatenation. We’re giving it a recipe: some String \u0001 other String \u0001, which in this case, contains two placeholders. If we concatenate more variables, there will be more placeholders, but it will still be a single String in the Constant Pool.</p><p>The cool thing about invokedynamic approach is that when the newer JDK versions appear with newer concatenation techniques, the bytecode can stay the same while the bootstrap method does something more advanced (more on the current implementation a bit later).</p><p>What about example #3? In this case, the following instruction will be executed in a loop:</p><pre>16: invokedynamic #9,  0  // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;</pre><p>This will lead to unnecessary amounts of String instances being allocated.</p><h4>String::format</h4><p>I had a preconception that String::format is a better alternative to the+ operator. This method can indeed offer improved readability in some cases and supports localization. Some basic benchmarking shows slightly better performance compared to concatenation. However, implementing the format method creates a new String for each parameter.</p><p>Let’s run a small experiment:</p><pre>int firstValue = 12345;<br>int secondValue = 987654321;<br>int thirdValue = 117117;<br>String test = String.format(&quot;test %s and %s and %s&quot;, firstValue, secondValue, thirdValue);</pre><p>In the bytecode, we’re placing all the values on the operand stack and simply invoking a static method:</p><pre>34: invokestatic  #15  // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;</pre><p>Now, let’s look at the heap dump taken after this method is invoked. For that, let’s compile the program and run it with the garbage collector disabled (so it doesn’t collect the String instances before we can take a look at them):</p><pre>javac --enable-preview --source=21 Main.java<br>java --enable-preview -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC Main</pre><p>I am using VisualVM to create a heap dump. In the String instances section, I can see the following values:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*t9nJzZKfWrrwCSGBaQ33YA.png" /></figure><h4>Java newest String templates</h4><p>The new String template feature is good, but not because it uses memory efficiently. Actually, for basic cases, it behaves exactly the same as String concatenation under the hood. It utilizes the invokedynamic instruction passes the recipe over to the bootstrap method allowing it to do its magic.</p><p>The String templates are amazing because they can redefine the way of template processing and allow us to create other types besides String (if we want to). I enjoyed reading this <a href="https://medium.com/@benweidig/looking-at-java-21-string-templates-17d9f655e7f3">article</a> that tells more about it.</p><h4>invokedynamic approach</h4><p>We figured out that invokedynamic is used for most of the modern String concatenation/interpolation techniques in Java.</p><p>Is it perfect? In terms of redundant String allocation, it’s not.</p><p>We’ve seen that we’re passing the recipe (template with placeholders) as a single String. Now, if the values that have to be inserted into the placeholders are coming from the Constant Pool (the \u0002 placeholder code), then there will be no extra Strings allocated.</p><p>On the other hand, if we’re using normal variables, the placeholder code will be \u0001. In this case, at runtime, the bootstrap method creates a separate String instance for every piece between placeholders, and these Strings are combined with the parameters to construct a final String.</p><p>To see the proof of that, let’s consider this small example:</p><pre>int firstValue = 12345;<br>int secondValue = 987654321;<br>int thirdValue = 117117;<br><br>// alright, we can use the fancy string templates:<br>String test = STR.&quot;test \{firstValue} and \{secondValue} and \{thirdValue}&quot;;<br><br>// but this line would result in exactly identical bytecode:<br>// String test = &quot;test &quot; + firstValue + &quot; and &quot; + secondValue + &quot; and &quot; + thirdValue;</pre><p>In the bytecode, we see the invokedynamic with the single String which contains the recipe:</p><pre>13: invokedynamic #9,  0  // InvokeDynamic #0:makeConcatWithConstants:(III)Ljava/lang/String;<br><br>...<br><br>BootstrapMethods:<br>  0: #27 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;<br>    Method arguments:<br>      #25 test \u0001 and \u0001 and \u0001</pre><p>If we run the program with the garbage collector disabled and take the heap dump, we will see the following String instances (plus the resulting String, of course):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sWalMga-Iy_5CtenVYb6pQ.png" /></figure><p>For comparison, if we used the StringBuilder instead, it would look like this:</p><pre>String test = new StringBuilder()<br>        .append(&quot;test &quot;)<br>        .append(firstValue)<br>        .append(&quot; and &quot;)<br>        .append(secondValue)<br>        .append(&quot; and &quot;)<br>        .append(thirdValue)<br>        .toString();</pre><p>There would be only one “ and “ value allocated even if we type it in twice. There will be three String instances: two fragments and the result.</p><h4>What about Kotlin?</h4><p>I apologize for the lack of fun in this section, but Kotlin (1.9.0) behaves similarly to Java under the hood. The + operator as well as the plus() function and String interpolation syntax (for example, val testStr = “this is $testNum test”) all use invokedynamic.</p><p>Some versions ago, both Java and Kotlin were using StringBuilder internally to optimize String concatenation. Now they use invokedynamic, which allows to split the concatenation logic away from the bytecode (it’s sitting in the bootstrap and target methods). The implementation will probably evolve, and other JVM languages can benefit from it without making any changes (or with minor changes).</p><h3>Conclusion</h3><p>Regarding best practices, we probably don’t want to go against conventions. But we do want to know what’s happening inside.</p><p>What should we use? I only have the classic answer to this: it depends!</p><p>Perhaps, it’s not too bad to use regular + operator sometimes? Maybe it does look more readable in some cases (teeny tiny percent).</p><p>If we care about efficiency, we‘re better off using a StringBuilder or a StringBuffer. StringBuffer also gives all kinds of thread safety. String::format seems to work somewhat fast, but StringBuilder is a lot faster. The downside of StringBuilder is verbosity.</p><p>If we’re not too concerned about memory and speed but want to use powerful help in formatting and readability, String templates will be a great choice. Remember that they might become more efficient in newer versions and are much more than just a String interpolation mechanism.</p><p>Thank you for reading.</p><p>* The <a href="https://openjdk.org/jeps/430">String Templates</a> are a Preview feature in Java 21. This means that this feature is still being tested by the community; it’s not final and may change in the next versions. I’m not suggesting using preview features in production, but simply inviting you to analyse it alongside other concatenation techniques from the perspective of the internal workings.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=772752607d43" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/java-21-so-how-should-we-construct-strings-now-772752607d43">Java 21: So How Should We Construct Strings Now?</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>