<?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 Hyuni Kim on Medium]]></title>
        <description><![CDATA[Stories by Hyuni Kim on Medium]]></description>
        <link>https://medium.com/@jbhyunikim?source=rss-19b116276bbd------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*EjnMnCeHKtHofJ9ARJWdvQ.jpeg</url>
            <title>Stories by Hyuni Kim on Medium</title>
            <link>https://medium.com/@jbhyunikim?source=rss-19b116276bbd------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 30 May 2026 09:13:26 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@jbhyunikim/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[Well Synchronized, Yet Asynchronous — Concurrent Orders]]></title>
            <link>https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-concurrent-orders-67c695a95e61?source=rss-19b116276bbd------2</link>
            <guid isPermaLink="false">https://medium.com/p/67c695a95e61</guid>
            <category><![CDATA[multithreading]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Hyuni Kim]]></dc:creator>
            <pubDate>Sat, 05 Aug 2023 14:07:29 GMT</pubDate>
            <atom:updated>2023-08-23T00:31:03.839Z</atom:updated>
            <content:encoded><![CDATA[<h3>Well Synchronized, Yet Asynchronous — Concurrent Orders</h3><h4>A journey to write efficient multithreaded code</h4><p><em>This article is a part of a </em><strong><em>Well Synchronized, Yet Asynchronous </em></strong><em>series. Check out the previous article to join the journey!</em></p><p><a href="https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-immutable-menu-d2a8e5f5cd48">Well Synchronized, Yet Asynchronous — Immutable Menu</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aT-xRCugM4sOTtGUpXziHQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/ko/@terasproductions">Frank Zhang</a> from <a href="https://unsplash.com/ko">Unsplash</a></figcaption></figure><p>Once customers check the Bigtaurant’s menu simultaneously, they are ready to place their orders. Bob’s implementation was inefficient, and customers were complaining about waiting too long. We can help Bob improve his application’s performance by using concurrent collections in Java.</p><h3>Bob’s original implementation</h3><p>Bob wanted to ensure that dishes were prepared and served in the same order that customers ordered them. To do this, he decided to use a Queue per dish to hold the order of customers who ordered the dish. He then used a Map to map each dish to its corresponding Queue.</p><pre>Map&lt;Dish, Queue&lt;Integer&gt;&gt; orderMap = new HashMap&lt;&gt;();</pre><p>When a customer orders a dish, their id is be inserted into the queue for that dish. This way, Bigtaurant knows which customer ordered the dish first and can serve the food when it’s ready.</p><p>Here’s the order method from Bob.</p><pre>public synchronized void order(int customerId, Dish dish) {<br>    if (!orderMap.containsKey(dish)) {<br>        orderMap.put(dish, new LinkedList&lt;&gt;());<br>    }<br><br>    orderMap.get(dish).add(customerId);<br>}</pre><p>To work with orderMap instance safely, Bob wrapped the method with synchronized keyword. This made the method thread-safe, but it also caused some inefficiency.</p><h4>Issues</h4><p>Just like the problem that the synchronized block caused when customers were reading the menu, the synchronized in order() method also forces customers to order sequentially. This means that one customer has to wait if there are other customers who are ready to order.</p><p>As you saw in the previous article, this will slow down the application and make customers complain about not taking their orders. Bob’s biggest mistake here is to use collections that are not designed for thread-safety. We can help Bob by replacing these into concurrent collections.</p><h3>Concurrent Collections</h3><p>Concurrent collections are a set of classes in the Java Collections Framework that provide thread-safe access to data structure. They are preferred over basic collections like Map or Queue because they make asynchronous programming much simpler by eliminating the need for explicit synchronization.</p><p>There are a number of concurrent collections that Java have.</p><ul><li><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html">ConcurrentHashMap</a>: A thread-safe implementation of the Map interface. It maintains the order of elements in insertion order.</li><li><a href="https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/java/util/concurrent/ConcurrentLinkedQueue.html">ConcurrentLinkedQueue</a>: A thread-safe implementation of the Queue interface. It maintains the FIFO (first in, first out) order of elements.</li><li><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArrayList.html">CopyOnWriteArrayList</a>: A thread-safe implementation of the ArrayList interface. It creates a copy of the array when it is modified, which ensures that no threads are reading stale data.</li><li><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArraySet.html">CopyOnWriteArraySet</a>: A thread-safe implementation of the HashSet interface. It works similarly to CopyOnWriteArrayList, but it is used to store sets of elements.</li><li><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentSkipListMap.html">ConcurrentSkipListMap</a>: A thread-safe implementation of the Map interface that is sorted by its keys. It is a good choice for applications that require concurrent access to a sorted map.</li><li><a href="https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentSkipListSet.html">ConcurrentSkipListSet</a>: A thread-safe implementation of the Set interface that is sorted by its elements. It is a good choice for applications that require concurrent access to a sorted set.</li></ul><p>The names of the collections are quite straight-forward and you can choose the concurrent collection that matches your needs. Here, we will use ConcurrentHashMap and ConcurrentLinkedQueue.</p><h4>ConcurrentHashMap</h4><p>ConcurrentHashMap is a concrete and concurrent hash table implementation of the Map interface. It is thread-safe and allows multiple threads to access and modify it.</p><p>From Bob’s implementation, we can replace HashMap with ConcurrentHashMap. We can also have the orderMap as ConcurrentMap to imply that it is thread-safe.</p><pre>private static final ConcurrentMap&lt;Dish, Queue&lt;Integer&gt;&gt; orderMap<br>            = new ConcurrentHashMap&lt;&gt;();</pre><p>Now that we have replaced HashMap with ConcurrentHashMap, the Map operations are thread-safe. We no longer have to make the whole order() method synchronized. However, the Queue is still not thread-safe. Let’s go fix that right now.</p><h4>ConcurrentLinkedQueue</h4><p>ConcurrentLinkedQueue is a thread-safe implementation of the Queue interface. ConcurrentLinkedQueue is a thread-safe implementation of the Queue interface. It maintains the FIFO order of elements. ConcurrentLinkedQueue can be a great option if you need a thread-safe queue.</p><p>In the order() method, we can replace the instantiation of LinkedList with ConcurrentLinkedQueue to ensure thread-safety.</p><pre>public void order(int customerId, Dish dish) {<br>    if (!orderMap.containsKey(dish)) {<br>        orderMap.put(dish, new ConcurrentLinkedQueue&lt;&gt;());<br>    }<br><br>    orderMap.get(dish).add(customerId);<br>}</pre><h3>Conclusion</h3><p>We now have a thread-safe order() method without a synchronized keyword. It is more efficient than the previous implementation and it was a simple change that had a huge impact.</p><p>Making your code thread-safe efficiently does not require extensive work. Instead. it involves a combination of small enhancements. See you on the next installment!</p><h4>Check out my other stories!</h4><p>The beginning of the Well Synchronized, Yet Asynchronous series:</p><p><a href="https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-bigtaurant-opens-8a0c5269b546">Well Synchronized, Yet Asynchronous — Bigtaurant Opens!</a></p><p>Multithreading in Java:</p><p><a href="https://medium.com/@jbhyunikim/5-multithreading-options-in-java-54905c657b2b">5 Multithreading Options in Java</a></p><p>Code sharing with static <em>vs</em> Dpendency Injection</p><p><a href="https://medium.com/@jbhyunikim/unleashing-the-java-dependency-dilemma-static-classes-vs-dependency-injection-showdown-b2a053bc841">How Do I Provide My Method? With “static” or Through Dependency Injection?</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=67c695a95e61" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Well Synchronized, Yet Asynchronous — Immutable Menu]]></title>
            <link>https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-immutable-menu-d2a8e5f5cd48?source=rss-19b116276bbd------2</link>
            <guid isPermaLink="false">https://medium.com/p/d2a8e5f5cd48</guid>
            <category><![CDATA[immutability]]></category>
            <category><![CDATA[synchronization]]></category>
            <category><![CDATA[multithreading]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Hyuni Kim]]></dc:creator>
            <pubDate>Thu, 27 Jul 2023 15:09:51 GMT</pubDate>
            <atom:updated>2023-08-05T10:45:39.621Z</atom:updated>
            <content:encoded><![CDATA[<h3>Well Synchronized, Yet Asynchronous — Immutable Menu</h3><h4>A journey to write efficient multithreaded code</h4><p><em>This article is a part of a </em><strong><em>Well Synchronized, Yet Asynchronous </em></strong><em>series. Check out the beginning of the journey below.</em></p><p><a href="https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-bigtaurant-opens-8a0c5269b546">Well Synchronized, Yet Asynchronous — Bigtaurant Opens!</a></p><p>In this article, we will help Bob on showing the Bigtaurant’s menu to the customers. We will mainly focus on:</p><ul><li>Risks of sharing mutable instances</li><li>Data class</li><li>Record</li><li>Immutable list</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KqypUt76fBoXVbRJw4OBSA.png" /><figcaption>Photo by my mom in Bangkok</figcaption></figure><h3>Bob’s original implementation</h3><p>Bigtaurant serves various menus. Bob tried his best to let customers read the menu efficiently, but found a lot of issues.</p><h4>Menu</h4><p>Here’s the Dish class that Bob wrote.</p><pre>package wsya.dish;<br><br>public class Dish {<br>    public String name;<br>    public int price;<br><br>    public Dish(String name, int price) {<br>        this.name = name;<br>        this.price = price;<br>    }<br><br>    @Override<br>    public String toString() {<br>        return &quot;{&quot; + name + &quot; : &quot; + price + &quot;}&quot;;<br>    }<br>}</pre><p>He then created an array to hold the menu they have.</p><pre>private static final Menu[] menu = {<br>        new Menu(&quot;CheeseBurger&quot;, 9.0),<br>        new Menu(&quot;OnionBurger&quot;, 8.5),<br>        new Menu(&quot;CheesePizza&quot;, 18.0),<br>        new Menu(&quot;PepperoniPizza&quot;, 19.5),<br>        new Menu(&quot;Coca Cola&quot;, 2.5),<br>};</pre><h4>Customer</h4><p>When customers enter, they check the menu. Bob smartly marked the class abstract and let the subclasses implement checkMenu() in their own way. Because the menus instance is shared, Bob wrapped the checkMenu() call with a synchronized block.</p><pre>package wsya;<br><br>import wsya.menu.Dish;<br><br>public abstract class CustomerRunnable implements Runnable {<br>    private final Dish[] menu;<br><br>    public CustomerRunnable(Menu[] menu) {<br>        this.menu = menu;<br>    }<br><br>    @Override<br>    public void run() {<br>        synchronized (menu) {<br>            checkMenu(menu);<br>        }<br>    }<br><br>    protected abstract void checkMenu(Dish[] menu);<br>}</pre><p>Bigtaurant is so loved that 10 people (which is so many that I can’t even imagine) were willing to enter. Bob created a thread pool with 5 threads using an <a href="https://medium.com/@jbhyunikim/5-multithreading-options-in-java-54905c657b2b">ExecutorService</a> to serve the customers.</p><pre><br>// 5servers<br>ExecutorService executorService = Executors.newFixedThreadPool(5);<br><br>// Handle 10 customers<br>for (int i = 0; i &lt; 10; i++) {<br>    executorService.submit(new CustomerRunnable(menus) {<br>        @Override<br>        protected void checkMenu(Menu[] menu) {<br>            // Do customized menu checking.<br>        }<br>    });<br>}<br><br>executorService.shutdown();</pre><h3>Issues</h3><p>Bob put the customizable block in synchronized to prevent any troubles. What can possibly go wrong?</p><h4>Only one customer can read the menu at a time</h4><p>Because the checkMenu() is locked with menu instance, no two customers can read the menu at the same time. It takes some time for the customers to read the menu, say 1 second.</p><pre>int customerId = i;<br>executorService.submit(new CustomerRunnable(menus) {<br>    @Override<br>    protected void checkMenu(Menu[] menu) {<br>        System.out.println(&quot;[&quot; + new Timestamp(System.currentTimeMillis()) + &quot;] &quot; +<br>                &quot;Customer &quot; + customerId + &quot; is reading menu.&quot;);<br>        System.out.println(&quot;\t&quot; + Arrays.toString(menu));<br><br>        try {<br>            Thread.sleep(1000);<br>        } catch (InterruptedException e) {<br>            throw new RuntimeException(e);<br>        }<br>    }<br>});</pre><p>When running the code, you can see that customers are reading the menu one next to one.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/514/1*40osTeox-3nk3Z9zi6EwmA.gif" /></figure><p>This makes multithreading useless. It’s just same as having everything synchronized. This can especially be problematic when one customer takes a long time reading a menu. The customer will block all other customers, lowering the efficiency in a huge rate.</p><h4>Customers doodling</h4><p>A few customers had a complaint about not finding the dish they want. They ended up with replacing them into their own.</p><pre>System.out.println(&quot;[&quot; + new Timestamp(System.currentTimeMillis()) + &quot;] &quot; +<br>        &quot;Customer &quot; + customerId + &quot; is reading menu.&quot;);<br>System.out.println(&quot;\t&quot; + Arrays.toString(menu));<br><br>if (customerId == 2) {<br>    menu[2] = new Menu(&quot;My Favorite Dish!&quot;, 100000);<br>} else if (customerId == 4) {<br>    menu[4].name = &quot;I hate this!&quot;;<br>}<br><br>try {<br>    Thread.sleep(1000);<br>} catch (InterruptedException e) {<br>    throw new RuntimeException(e);<br>}</pre><p>Below is what the customers read.</p><pre>[2023-07-27 23:14:25.914] Customer 0 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br>[2023-07-27 23:14:26.946] Customer 4 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br>[2023-07-27 23:14:27.951] Customer 3 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:28.955] Customer 2 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:29.96] Customer 1 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {My Favorite Dish! : 100000.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:30.962] Customer 8 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {My Favorite Dish! : 100000.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:31.973] Customer 7 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {My Favorite Dish! : 100000.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:32.99] Customer 6 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {My Favorite Dish! : 100000.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:33.999] Customer 5 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {My Favorite Dish! : 100000.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]<br>[2023-07-27 23:14:35.003] Customer 9 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {My Favorite Dish! : 100000.0}, {PepperoniPizza : 19.5}, {I hate this! : 2.5}]</pre><p>Customers reading after customer 2 are seeing “My Favorite Dish!” instead of CheesePizza. Similarly, customers after customer 4 are seeing the menu with “I hate this!” instead of Coca Cola.</p><p>After seeing the modified menu, some might even order them and get rejected, which is an unpleasant experience.</p><h3>Immutables!</h3><p>What can we do to avoid this hazard? Menu is not a thing that can be changed. Once set, that’s done. Nobody can change the menu that’s already defined. If you want to change some ingredients or recipes, that’s a separate dish.</p><h4>Immutable Class</h4><p>To prevent overriding the fields’ values, which is what customer 4 did, we can make each menu immutable so that no customer codes can change the menu we provided. This can be done by marking the fields final.</p><pre>public class Dish{<br>    public final String name;<br>    public final double price;<br><br>    public Dish(String name, double price) {<br>        this.name = name;<br>        this.price = price;<br>    }<br><br>    ...<br>}</pre><p>Now customers will only be able to read the name and price. If the customer codes try to set the value to something else, they will face a compile error.</p><p>These immutable classes are often referred to as <strong>Data Classes,</strong> and many other languages support creating them at their language level. Java also provides record from Java 16.</p><p>record provides a functionality to define and initialize public final fields directly from the constructor and implements equals(), hashCode(), and toString() based on its fields.</p><p>Instead of making Dish a class and writing public finals with a constructor, you can rewrite it as follows.</p><pre>public record Dish(String name, double price) {<br><br>    @Override<br>    public String toString() {<br>        return &quot;{&quot; + name + &quot; : &quot; + price + &quot;}&quot;;<br>    }<br>}</pre><p>The constructor and the fields definition became much more concise. Also, note that record implements toString(), so our toString() implementation is not really necessary to see the value of each field, but is only there to construct the String in the format of our preference.</p><h4>Immutable List</h4><p>One concern is still remaining. Customer codes can replace the menu itself into a totally different menu, just as what customer 2 did. Arrays are naturally mutable. To have immutability, we will use an immutable list.</p><p>The most simple and general way to create one is using List.of() method. This method takes multiple parameters and returns an immutable list that contains the given parameters as its elements.</p><p>The new menu with immutability is as follows:</p><pre>private static final List&lt;Menu&gt; menu = List.of(<br>        new Dish(&quot;CheeseBurger&quot;, 9.0),<br>        new Dish(&quot;OnionBurger&quot;, 8.5),<br>        new Dish(&quot;CheesePizza&quot;, 18.0),<br>        new Dish(&quot;PepperoniPizza&quot;, 19.5),<br>        new Dish(&quot;Coca Cola&quot;, 2.5));</pre><p>The menu list are now immutable, not able to add, delete, or replace.</p><h3>Synchronization</h3><p>Customer codes are no longer able to modify the menu. They will raise a compile error when they try to update a record, and will have no luck with changing the immutable list.</p><p>Immutables are free from synchronization as other threads are guaranteed to not change the values. This means, synchronized can be removed from the CustomerRunnable’s run() method. (Also note that the class now holds List&lt;Dish&gt; instead of Dish[].)</p><pre>public abstract class CustomerRunnable implements Runnable {<br>    private final List&lt;Dish&gt; menu;<br><br>    public CustomerRunnable(List&lt;Dish&gt; menu) {<br>        this.menu = menu;<br>    }<br><br>    @Override<br>    public void run() {<br>        checkMenu(menu);<br>    }<br><br>    protected abstract void checkMenu(List&lt;Dish&gt; menu);<br>}</pre><p>Running the code again, you’ll see that customers are reading the menu at the same time.</p><pre>[2023-07-27 23:35:43.867] Customer 1 is reading menu.<br>[2023-07-27 23:35:43.867] Customer 0 is reading menu.<br>[2023-07-27 23:35:43.867] Customer 3 is reading menu.<br>[2023-07-27 23:35:43.867] Customer 2 is reading menu.<br>[2023-07-27 23:35:43.867] Customer 4 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br>[2023-07-27 23:35:44.892] Customer 5 is reading menu.<br>[2023-07-27 23:35:44.892] Customer 6 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br>[2023-07-27 23:35:44.893] Customer 7 is reading menu.<br>[2023-07-27 23:35:44.893] Customer 8 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]<br>[2023-07-27 23:35:44.895] Customer 9 is reading menu.<br> [{CheeseBurger : 9.0}, {OnionBurger : 8.5}, {CheesePizza : 18.0}, {PepperoniPizza : 19.5}, {Coca Cola : 2.5}]</pre><p>Looking into the details, you’ll see that five customers start reading together. This is because we’re using a thread pool with five threads. Each thread takes a customer, and after one second, when the customers have finished reading the menu, the next set of customers can start reading.</p><h3>Conclusion</h3><p>Bob was incredibly happy to see the optimized result. Using immutables, you made 10 customers read the menu in two seconds, which previously took 10 seconds. This is a huge improvement!</p><p>There are a lot of more enhancements to be made to Bob’s other codes. The journey has just been started. Hold on tight!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2a8e5f5cd48" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Well Synchronized, Yet Asynchronous — Bigtaurant Opens!]]></title>
            <link>https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-bigtaurant-opens-8a0c5269b546?source=rss-19b116276bbd------2</link>
            <guid isPermaLink="false">https://medium.com/p/8a0c5269b546</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[multithreading]]></category>
            <dc:creator><![CDATA[Hyuni Kim]]></dc:creator>
            <pubDate>Fri, 21 Jul 2023 11:11:37 GMT</pubDate>
            <atom:updated>2023-08-05T12:37:32.495Z</atom:updated>
            <content:encoded><![CDATA[<h3>Well Synchronized, Yet Asynchronous — Bigtaurant Opens!</h3><h4>A journey to write efficient multithreaded code</h4><p><em>If you are new to multithreading, check out my previous article to grasp on how you can apply it to your application. It shows you ways to easily boost your application’s performance.</em></p><p><a href="https://medium.com/@jbhyunikim/5-multithreading-options-in-java-54905c657b2b">5 Multithreading Options in Java</a></p><p>Multithreading is a prominent aspect of modern applications. It helps the application leverage the full power of computing resources. However, excessive use of synchronized or other multithreading techniques can cause negative impacts, such as increased latency, deadlocks, etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oF4A3VvreI8yBVMeUMqEVA.jpeg" /><figcaption>Photo by me, in Pattaya</figcaption></figure><p>This article is the beginning of a series, <strong>“Well Synchronized, Yet Asynchronous”</strong>. In this series, we will go through steps to build an efficient multithreaded application. Each article will cover one synchronization technique. Let’s begin the journey!</p><h3>Bigtaurant Opens!</h3><p>Bob is an owner of a big restaurant, Bigtaurant. With countless customers visiting everyday, Bob wants to build an application to manage the restaurant. There are so many things happening at the same time in Bigtaurant so Bob wants threads to play a role.</p><p>To avoid mess, Bob puts everything into synchronized blocks, making every part of the application <em>Thread-Safe</em>. This includes:</p><ol><li><a href="https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-immutable-menu-d2a8e5f5cd48">Showing Menu</a></li><li>Taking Orders</li><li>Cooking &amp; Serving</li><li>Controlling Music</li><li>Handling Payments</li></ol><p>The happiness of launching a new application didn’t last long. Bob finds that the application is lagging and only one of the many threads is running at a time, leaving other threads waiting for it to finish.</p><h4>Bob’s mistakes</h4><p>Bob put everything into synchronized blocks. The easiest way to make something thread-safe is indeed to mark the method synchronized and it’s easy to get lured or tempted. Too much use of synchronized when it’s not necessary, however, makes threads useless.</p><p>Consider the following code that Bob wrote.</p><pre>public class BigtaurantApplication {<br> public synchronized void order(int customerId, Dish dish) { ... }<br><br> public synchronized void changeMusic(Music music) { ... }<br>}</pre><p>synchronized methods are locked on the instance. In this case, the instance of BigtaurantApplication. This means that only one synchronized method can be called at the same time. You can see that it is quite inefficient. Making an order and changing the music have nothing to do with each other and don’t have to run one next to one. synchronized methods can lay this kind of inefficiency very easily and always be used with care.</p><p>Let’s say Bob somehow managed to separate them and made them run in parallel. Here is what Bob wrote for the order() method.</p><pre>public void order(int customerId, Dish dish) {<br>  synchronized (orderMap) {<br>    Queue&lt;Integer&gt; customersWaitingForFood = orderMap.get(dish);<br>    customersWaitingForFood.add(customerId);<br>  }<br>}</pre><p>Bob used Map and Queue to manage the customers who ordered each menu. It looks better than the previous code, as it can run at the same time with changeMusic, but it’s still not efficient enough.</p><p>Because it is locked on the orderMap instance, only one customer can order their food at once. If one customer is ordering food, all the customers ready to make an order should wait.</p><p>Bob desperately wants the application to be faster and needs a lot of help on synchronization. Throughout the next several articles, we will help Bob rebuild his application by covering the following synchronization techniques:</p><ul><li>Immutables</li></ul><p><a href="https://medium.com/@jbhyunikim/well-synchronized-yet-asynchronous-immutable-menu-d2a8e5f5cd48">Well Synchronized, Yet Asynchronous — Immutable Menu</a></p><ul><li>Concurrent Collections</li><li>Producer &amp; Consumer pattern</li><li>Lock</li><li>Atomics</li></ul><p>Once we finish the journey, you will be able to use each synchronization method in their appropriate situation. Bob will also love the outcome.</p><p>Stay tuned!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8a0c5269b546" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Multithreading Options in Java]]></title>
            <link>https://medium.com/@jbhyunikim/5-multithreading-options-in-java-54905c657b2b?source=rss-19b116276bbd------2</link>
            <guid isPermaLink="false">https://medium.com/p/54905c657b2b</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[multithreading]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Hyuni Kim]]></dc:creator>
            <pubDate>Wed, 19 Jul 2023 06:59:15 GMT</pubDate>
            <atom:updated>2023-07-19T06:59:15.223Z</atom:updated>
            <content:encoded><![CDATA[<h4>Make your Java application efficient and asynchronous with multithreading</h4><p>Computing power and performance have skyrocketed since their invention. The number of cores and their potentials are like nothing before, giving your application infinite possibilities. Despite the vast improvement, a single-threaded application can only utilize a maximum of one core and cannot benefit from the multi-cores that most modern computers have.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E8aisoClHQRF_938e_Yg4g.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/ko/@neelakshi_singh_">Neelakshi Singh</a> from <a href="https://unsplash.com/ko">Unsplash</a></figcaption></figure><p>If you feel your application is lagging, compared to other applications in the world that do way more work, it being single-threaded might be the culprit. The solution: multithreading. If this is what you need, consider applying one of the following methods.</p><ol><li><strong><em>Thread</em></strong></li><li><strong><em>Parallel Streams</em></strong></li><li><strong><em>ExecutorService</em></strong></li><li><strong><em>ForkJoinPool</em></strong></li><li><strong><em>CompletableFuture</em></strong></li></ol><p>When used appropriately, it could shake up your world and launch your career. Let’s see how you can transform your application into an efficient multithreaded one.</p><h3>1. Thread</h3><p>The first option is to use the Thread class. This way, you can control threads directly from their creation to management. Here’s an example.</p><p>CustomTask counts from 0 to count - 1 every 50 milliseconds.</p><pre>public class CustomTask implements Runnable {<br>    private final String name;<br>    private final int count;<br><br>    CustomTask(String name, int count) {<br>        this.name = name;<br>        this.count = count;<br>    }<br><br>    @Override<br>    public void run() {<br>        for (int i = 0; i &lt; count; i++) {<br>            System.out.println(name + &quot;-&quot; + i + &quot; from &quot; +<br>                    Thread.currentThread().getName());<br>            try {<br>                Thread.sleep(50);<br>            } catch (InterruptedException e) {<br>                throw new RuntimeException(e);<br>            }<br>        }<br>    }<br>}</pre><p>a, b, and c are the three instances of this class.</p><pre>Thread a = new Thread(new CustomTask(&quot;a&quot;, 5));<br>Thread b = new Thread(new CustomTask(&quot;b&quot;, 10));<br>Thread c = new Thread(new CustomTask(&quot;c&quot;, 5));</pre><p>Notice that b is expected to count twice as much as others. You want to run b while a and c run sequentially.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/328/1*hN9Jlv6820zOUubxylqDlA.png" /></figure><p>You can implement this behavior very easily.</p><pre>// a, b start running first.<br>a.start();<br>b.start();<br><br>// c starts after a is finished.<br>a.join();<br>c.start();</pre><p>And here is the result.</p><pre>a-0 from Thread-0<br>b-0 from Thread-1<br>b-1 from Thread-1<br>a-1 from Thread-0<br>b-2 from Thread-1<br>a-2 from Thread-0<br>b-3 from Thread-1<br>a-3 from Thread-0<br>b-4 from Thread-1<br>a-4 from Thread-0<br>b-5 from Thread-1<br>c-0 from Thread-2<br>b-6 from Thread-1<br>c-1 from Thread-2<br>b-7 from Thread-1<br>c-2 from Thread-2<br>b-8 from Thread-1<br>c-3 from Thread-2<br>b-9 from Thread-1<br>c-4 from Thread-2</pre><p>a and b started running together, printing out in turns. c began producing after a is done. Also, all of them are running in different threads. By manually creating instances of Thread, you can have full control over them.</p><p>However, be mindful that low-level thread handling requires synchronization and resource-management too, which can be more error-prone and complex.</p><h3>2. Parallel Streams</h3><p>Parallel streams are effective when you have to apply identical, repetitive, and independent tasks to all the elements in a large collection.</p><p>For example, image resizing is a heavy task to run sequentially; it will take forever to finish when you have a number of them. In this case, you can resize them in parallel as follows.</p><pre>private static List&lt;BufferedImage&gt; resizeAll(List&lt;BufferedImage&gt; sourceImages,<br>                                             int width, int height) {<br>    return sourceImages<br>            .parallelStream()<br>            .map(source -&gt; resize(source, width, height))<br>            .toList();<br>}</pre><p>This way, images will be resized simultaneously, saving you much precious time.</p><h3>3. ExecutorService</h3><p>You can consider using ExecutorService when the implementation doesn’t require precise thread controls. ExecutorService provides higher-level abstraction for thread management, including thread pooling, task scheduling, and resource management.</p><p>ExecutorService is an interface and its most general usage is the thread pool. Suppose that you have piles of asynchronous tasks stacking up, but running them all at the same time — each of them taking up one thread — just seems too much. Thread pools can help you by limiting the maximum number of threads to use.</p><p>Below, we’re using ExecutorService instantiated by Executors.newFixedThreadPool() to run 10 tasks with 3 threads. Each task will only print a single line. Note that we’re reusing the CustomTask defined in the previous section.</p><pre>ExecutorService executorService = Executors.newFixedThreadPool(3);<br><br>for (int i = 0; i &lt; 10; i++) {<br>    executorService.submit(new CustomTask(String.valueOf(i), 1));<br>}<br><br>executorService.shutdown();</pre><p>This prints out the following.</p><pre>0-0 from pool-1-thread-1<br>2-0 from pool-1-thread-3<br>1-0 from pool-1-thread-2<br>4-0 from pool-1-thread-3<br>3-0 from pool-1-thread-2<br>5-0 from pool-1-thread-1<br>6-0 from pool-1-thread-1<br>7-0 from pool-1-thread-3<br>8-0 from pool-1-thread-2<br>9-0 from pool-1-thread-3</pre><p>10 tasks are running in 3 threads. By limiting the number of threads used for specific tasks, you can assign the number of threads depending on the priorities: more threads for important and frequent tasks, and less threads for trivial or occasional tasks. With high efficiency and simplicity, ExecutorService is a preferred option for most multithreading scenarios.</p><p>If you feel the need for more control and flexibility, check out ThreadPoolExecutor, which is an actual implementation of ExecutorService that Executors.newFixedThreadPool() returns. You can directly create its instance or cast the returned ExecutorService instance to gain more control.</p><h3>4. ForkJoinPool</h3><p>ForkJoinPool is another type of thread pool, as its name implies. While it is used under the hood of a lot of other asynchronization methods, it is also very powerful for tasks that can be divided into smaller, and independent sub-tasks, which can be solved by divide-and-conquer strategy.</p><p>One such task is image resizing. Image resizing is a great example of a divide-and-conquer problem. With ForkJoinPool, you can divide the image into two, or four smaller images and resize them in parallel. The following demonstrates ImageResizeAction, which resizes the image into a given size.</p><pre>package multithreading;<br><br>import java.awt.image.BufferedImage;<br>import java.util.concurrent.RecursiveAction;<br><br>public class ImageResizeAction extends RecursiveAction {<br>    private static final int THRESHOLD = 100;<br><br>    private final BufferedImage sourceImage;<br>    private final BufferedImage targetImage;<br>    private final int startRow;<br>    private final int endRow;<br>    private final int targetWidth;<br>    private final int targetHeight;<br><br>    public ImageResizeAction(BufferedImage sourceImage,<br>                             BufferedImage targetImage,<br>                             int startRow, int endRow,<br>                             int targetWidth, int targetHeight) {<br>        this.sourceImage = sourceImage;<br>        this.targetImage = targetImage;<br>        this.startRow = startRow;<br>        this.endRow = endRow;<br>        this.targetWidth = targetWidth;<br>        this.targetHeight = targetHeight;<br>    }<br><br>    @Override<br>    protected void compute() {<br>        if (endRow - startRow &lt;= THRESHOLD) {<br>            resizeImage();<br>        } else {<br>            int midRow = startRow + (endRow - startRow) / 2;<br>            invokeAll(<br>                    new ImageResizeAction(sourceImage, targetImage,<br>                            startRow, midRow, targetWidth, targetHeight),<br>                    new ImageResizeAction(sourceImage, targetImage,<br>                            midRow, endRow, targetWidth, targetHeight)<br>            );<br>        }<br>    }<br><br>    private void resizeImage() {<br>        int sourceWidth = sourceImage.getWidth();<br>        double xScale = (double) targetWidth / sourceWidth;<br>        double yScale = (double) targetHeight / sourceImage.getHeight();<br><br>        for (int y = startRow; y &lt; endRow; y++) {<br>            for (int x = 0; x &lt; sourceWidth; x++) {<br>                int targetX = (int) (x * xScale);<br>                int targetY = (int) (y * yScale);<br>                int rgb = sourceImage.getRGB(x, y);<br>                targetImage.setRGB(targetX, targetY, rgb);<br>            }<br>        }<br>    }<br>}</pre><p>Note that ImageResizeAction inherits RecursiveAction. RecursiveAction is used to define the recursive resizing action. In this example, the image is divided into half and resized concurrently.</p><p>You can run the ImageResizeAction with the following code:</p><pre>public static void main(String[] args) throws IOException {<br>    String sourceImagePath = &quot;source_image.jpg&quot;;<br>    String targetImagePath = &quot;target_image.png&quot;;<br>    int targetWidth = 300;<br>    int targetHeight = 100;<br><br>    BufferedImage sourceImage = ImageIO.read(new File(sourceImagePath));<br>    BufferedImage targetImage = new BufferedImage(targetWidth, targetHeight,<br>            BufferedImage.TYPE_INT_RGB);<br><br>    ForkJoinPool forkJoinPool = new ForkJoinPool();<br>    forkJoinPool.invoke(new ImageResizeAction(sourceImage, targetImage,<br>            0, sourceImage.getHeight(), targetWidth, targetHeight));<br><br>    ImageIO.write(targetImage, &quot;png&quot;, new File(targetImagePath));<br><br>    System.out.println(&quot;Image resized successfully!&quot;);<br>}</pre><p>With the help of ForkJoinPool, you are now able to resize an image more efficiently, with more scalability, and with maximized resource usage.</p><h3>5. CompletableFuture</h3><p>With CompletableFuture, you can have full functionality of Future and a number of additional features. The most prominent feature of it is its ability to chain asynchronous operations, allowing you to build complex asynchronous pipelines.</p><pre>public static void main(String[] args) {<br>    CompletableFuture&lt;Void&gt; future = CompletableFuture.supplyAsync(() -&gt; {<br>        System.out.println(Thread.currentThread().getName());<br>        return &quot;Hyuni Kim&quot;;<br>    }).thenApply((data) -&gt; {<br>        System.out.println(Thread.currentThread().getName());<br>        return &quot;My name is &quot; + data;<br>    }).thenAccept((data) -&gt; {<br>        System.out.println(Thread.currentThread().getName());<br>        System.out.println(&quot;Result: &quot; + data);<br>    });<br><br>    future.join();<br>}</pre><p>The above code shows a key aspect of the CompletableFuture: chaining. With CompletableFuture.supplyAsync(), first CompletableFuture that results in a string is created and run. thenApply() accepts the result from the previous task and performs additional stuff, in this case, appending a string. Lastly, thenAccept() prints out the generated data. The result is as follows.</p><pre>ForkJoinPool.commonPool-worker-1<br>ForkJoinPool.commonPool-worker-1<br>ForkJoinPool.commonPool-worker-1<br>Result: My name is Hyuni Kim</pre><p>3 tasks were not run in the main thread, indicating that they were run in parallel with the main logic. When you have tasks that have results and should be chained, CompletableFuture will be a great option.</p><h3>Summary</h3><p>The absence of multithreading is like using only one pizza machine in a pizza store. It is inefficient and users will complain about it. Applying mutithreading is not difficult at all. With a simple change, you’ll be able to leverage the full power of computers today. Try multithreading now to unleash the new efficiency level of your application!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=54905c657b2b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Do I Provide My Method? With “static” or Through Dependency Injection?]]></title>
            <link>https://medium.com/@jbhyunikim/unleashing-the-java-dependency-dilemma-static-classes-vs-dependency-injection-showdown-b2a053bc841?source=rss-19b116276bbd------2</link>
            <guid isPermaLink="false">https://medium.com/p/b2a053bc841</guid>
            <category><![CDATA[dependency-injection]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[best-practices]]></category>
            <dc:creator><![CDATA[Hyuni Kim]]></dc:creator>
            <pubDate>Thu, 06 Jul 2023 06:23:34 GMT</pubDate>
            <atom:updated>2023-07-06T13:22:58.989Z</atom:updated>
            <content:encoded><![CDATA[<h4>Weighing the Pros and Cons of Static Classes and Dependency Injection for Optimal Code Organization</h4><p>When you write Java code, you don’t just put all the codes in a single file or class. Not only does it hurt readability, but it also lacks modularity and maintainability, making the code less scalable. Instead, we separate the codes into multiple files and classes, and reuse the behaviors defined in an appropriate class.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*vEP0k_D22Vcd9Ziv" /><figcaption>Image by Schwarez from Unsplash</figcaption></figure><p>Now, how about the features that are widely used and are not instance-specific? Say, checking whether the user is over 18, or converting the date into a string. We then face the dilemma: do we use static class or dependency injection? In this article, we go through the pros and cons, use cases, complexity, testing, and performance of them and give you a quick guide on which one to use. Let’s begin by looking into static classes and dependency injection in detail.</p><h3>Static class</h3><p>Static classes in Java are used to hold static members and can be accessed without any instantiation. Because of this, static classes usually group methods that perform generic tasks and don’t make use of any specific instance data.</p><h4>Examples</h4><p>Here’s an example. ConversionUtil class is a static class that provides static methods to convert different units.</p><pre>public class ConversionUtil {<br>    public static double cmToFeet(double cm) {<br>        return cm / 2.54 / 12;<br>    }<br>    <br>    public static double feetToCm(double feet) {<br>        return feet * 2.54 * 12;<br>    }<br>}</pre><p>Static classes can also hold constants, defined with static final keyword. Math class, a well-known static class built within Java, defines the constants this way.</p><pre>public final class Math {<br>    ...<br><br>    /**<br>     * The {@code double} value that is closer than any other to<br>     * &lt;i&gt;e&lt;/i&gt;, the base of the natural logarithms.<br>     */<br>    public static final double E = 2.7182818284590452354;<br>    /**<br>     * The {@code double} value that is closer than any other to<br>     * &lt;i&gt;pi&lt;/i&gt;, the ratio of the circumference of a circle to its<br>     * diameter.<br>     */<br>    public static final double PI = 3.14159265358979323846;<br>    /**<br>     * Constant by which to multiply an angular value in degrees to obtain a<br>     * angular value in radians.<br>     */<br>    private static final double DEGREES_TO_RADIANS = 0.017453292519943295;<br>    /**<br>     * Constant by which to multiply an angular value in radians to obtain a<br>     * angular value in degrees.<br>     */<br>    private static final double RADIANS_TO_DEGREES = 57.29577951308232;<br>    <br>    ...</pre><h4>Pros &amp; Cons</h4><p>Static classes are <strong>easy to write and access</strong>. We only have to write a class with static fields and any other classes can directly access them. Easy-to-write is a huge benefit for projects that need high velocity as it can make programmers focus on the business logic of an application.</p><p>However, static classes may introduce<strong> tight coupling</strong>, meaning that their use can create strong dependencies and interconnections between different components of an application. They can lead their dependencies to be tightly coupled to their specific implementation details because they are used without any object instantiation.</p><p>This also <strong>reduces testability</strong>. It’s not easy to stub or mock static methods with testing libraries like JUnit or Mockito. When writing code for the dependency that references the static members, you’ll have to write test codes that <strong>also </strong>test their behavior, which is not a desirable practice.</p><h3>Dependency Injection</h3><p>Dependency Injection (DI) is a design pattern that is widely used in Java development. It provides decoupling of the creation and management of dependencies, resulting in loose coupling and modular design.</p><p>The key concept of DI is the Inversion of Control (IoC). With DI, we don’t control the instance, specifically, object creation and dependency resolution. Instead, instances are provided to the dependents, typically through a constructor or setter.</p><h4>Examples</h4><p><a href="https://spring.io/">Spring</a> is one of the well-known frameworks with DI. In Spring, numerous classes are under DI’s management. For example, to handle a task around the User, you’ll write a UserService class and get it injected into your controller as follows:</p><pre>@RestController<br>public class UserController {<br>    private final UserService userService;<br><br>    public UserController(UserService userService) {<br>        this.userService = userService;<br>    }<br><br>    ...<br>}</pre><h4>Pros &amp; Cons</h4><p>With dependency injection, you don’t have to worry about creating and managing the instances. This allows dependents to depend on the interfaces rather than the concrete implementation, resulting in <strong>loose coupling</strong>. The dependents don’t need to know the implementation details and only consider what behavior they are calling results in.</p><p>DI is also <strong>strong at writing tests</strong>. Because of the loose coupling and the dependents not having to rely on the implementation of the dependencies, both dependents and dependencies can be tested independently.</p><p>The downside of the DI is, of course, the <strong>learning curve</strong> and the <strong>complexity</strong> of the application. DIs may not be very intuitive at first glance. You might not catch what creates the instances and how they wire into your class. However, DIs are not that complex and you will find yourself creating and injecting your instances in no time.</p><h3>What to use?</h3><p>We have gone through the meanings, and pros &amp; cons of both static classes and DI. So which one should we use?</p><p>Static classes are simple and easy while DIs are modular and scalable. So <strong>if your application is in its inception, you might want to write with static classes as they don’t require additional configuration and can be written fast.</strong></p><p>If your project is on track, you can consider the role of the class.<strong> If the class is just providing a few simple methods that don’t have to be explicitly tested</strong>, such as pow(), convertCmToFeet(), or replaceAll(), it will be fine to<strong> write it as a static class</strong>. In most cases, static classes will hold utility functions or global states.</p><p>In contrast, <strong>if the functionality that the class is providing is complex and should be tested</strong>, such as UserService that manages the methods and behaviors related to the Users, you might want to <strong>write it in a common class and inject it</strong>.</p><h3>Summary</h3><p>So we discussed static classes and DIs. Choosing which one to use is obviously up to you and your team members. However, it is important to make decisions with reasons. I hope this article helped you in finding rationales on which one to use. Thanks for reading!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b2a053bc841" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Can Streams Replace Loops in Java?]]></title>
            <link>https://medium.com/better-programming/can-streams-replace-loops-in-java-f56d4461743a?source=rss-19b116276bbd------2</link>
            <guid isPermaLink="false">https://medium.com/p/f56d4461743a</guid>
            <category><![CDATA[optimization]]></category>
            <category><![CDATA[loop]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[stream]]></category>
            <dc:creator><![CDATA[Hyuni Kim]]></dc:creator>
            <pubDate>Thu, 29 Jun 2023 14:57:09 GMT</pubDate>
            <atom:updated>2023-07-03T18:30:42.758Z</atom:updated>
            <content:encoded><![CDATA[<h4>Code readability, performance, and limitations of Streams</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*DzD1gNnK8D74R3JwlHfN3w.png" /><figcaption>Image generated with Stable Diffusion</figcaption></figure><p>The release of Java 8 was a momentous occasion in Java’s history. Streams and Lambdas were introduced, and they’re now being used widely. If you don’t know about Streams or have never heard of it, it’s completely fine. In most cases, loops will meet your needs, and you’ll have no trouble without Streams.</p><p>Then why do we need Streams? Can they replace or have benefits over loops? In this article, we will look into the code, compare performance, and see how well Streams do as a replacement for loops.</p><h3>Code Comparison</h3><p>Streams increase code complexity as they need classes, interfaces, and imports; loops are, in contrast, built-in by nature. This is true in some points, but not necessarily. Code complexity is a lot more than how many things you need to know. It’s more about how readable the code is. Let’s look at some examples.</p><h4>List of item names with a type</h4><p>Let’s say that we have a list of items and want the list of names of specific item types. Using loops, you will write the following:</p><pre>List&lt;String&gt; getItemNamesOfType(List&lt;Item&gt; items, Item.Type type) {<br>    List&lt;String&gt; itemNames = new ArrayList&lt;&gt;();<br>    for (Item item : items) {<br>        if (item.type() == type) {<br>            itemNames.add(item.name());<br>        }<br>    }<br>    return itemNames;<br>}</pre><p>Reading the code, you’ll see that a new ArrayList should be instantiated, and type check and add() call should be made in every loop. On the other hand, here’s the stream version of the same result:</p><pre>List&lt;String&gt; getItemNamesOfTypeStream(List&lt;Item&gt; items, Item.Type type) {<br>    return items.stream()<br>            .filter(item -&gt; item.type() == type)<br>            .map(item -&gt; item.name())<br>            .toList();<br>}</pre><p>With the help of Lambda, you can immediately catch that we’re first choosing the items with the given type, then getting the list of names of the filtered items. In this kind of code, the line-by-line flow aligns well with the logical flow.</p><h4>Generate a random list</h4><p>Let’s look at another example. In the Time Comparison section, we’ll review key Streams methods and compare their execution time with loops. For this, we need a random list of Items. Here is a snippet with a static method that gives a random Item:</p><pre>public record Item(Type type, String name) {<br>    public enum Type {<br>        WEAPON, ARMOR, HELMET, GLOVES, BOOTS,<br>    }<br><br>    private static final Random random = new Random();<br>    private static final String[] NAMES = {<br>            &quot;beginner&quot;,<br>            &quot;knight&quot;,<br>            &quot;king&quot;,<br>            &quot;dragon&quot;,<br>    };<br><br>    public static Item random() {<br>        return new Item(<br>                Type.values()[random.nextInt(Type.values().length)],<br>                NAMES[random.nextInt(NAMES.length)]);<br>    }<br>}</pre><p>Now, let’s make a list of random Items using loops. The code will look like this:</p><pre>List&lt;Item&gt; items = new ArrayList&lt;&gt;(100);<br>for (int i = 0; i &lt; 100; i++) {<br>    items.add(Item.random());<br>}</pre><p>The code with Streams looks like this:</p><pre>List&lt;Item&gt; items = Stream.generate(Item::random).limit(length).toList();</pre><p>A wonderful and easy-to-read code. Furthermore, the List returned by toList() method is unmodifiable, giving you immutability so you can share it anywhere in the code without worrying about side effects. This makes the code less error-prone, and the readers understand your code more easily.</p><p>Streams provide a variety of helpful methods that let you write concise codes. The most popular ones are:</p><ul><li>allMatch()</li><li>anyMatch()</li><li>count()</li><li>filter()</li><li>findFirst()</li><li>forEach()</li><li>map()</li><li>reduce()</li><li>sorted()</li><li>limit()</li><li>And more in <a href="https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html">Stream Javadoc</a></li></ul><h3>Performance</h3><p>Streams behave like loops in normal circumstances and have little or no effect on execution time. Let’s compare some major behaviors in Streams with loop implementations.</p><h4>Iterate elements</h4><p>When you have a collection of elements, there are a plethora of cases where you iterate all the elements inside the collection. In Streams, methods like forEach(), map(), reduce(), and filter() do this kind of whole-element iteration.</p><p>Let’s think of a case where we want to count each type of item inside a list. The code with the for loop will look like this:</p><pre>public Map&lt;Item.Type, Integer&gt; loop(List&lt;Item&gt; items) {<br>    Map&lt;Item.Type, Integer&gt; map = new HashMap&lt;&gt;();<br>    for (Item item : items) {<br>        map.compute(item.type(), (key, value) -&gt; {<br>            if (value == null) return 1;<br>            return value + 1;<br>        });<br>    }<br>    return map;<br>}</pre><p>The code with Streams looks like this:</p><pre>public Map&lt;Item.Type, Integer&gt; stream(List&lt;Item&gt; items) {<br>    return items.stream().collect(Collectors.toMap(<br>            Item::type,<br>            value -&gt; 1,<br>            Integer::sum));<br>}</pre><p>They look quite different, but how will they perform? Below is the table of average execution times of 100 tries:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe8e4bd596f0903a892adbf1214f3284/href">https://medium.com/media/fe8e4bd596f0903a892adbf1214f3284/href</a></iframe><p>As we can see in the above comparison table, Streams and loops show little execution time difference in iterating the whole list. This is the same for other Stream methods like map(), forEach(), reduce(), etc., in most cases.</p><h4>Optimization with parallel stream</h4><p>So, we found that Streams don’t perform better or worse than loops when iterating the list. However, there is an amazing thing about Streams that loops do not have: we can easily perform multi-thread computing with streams. All you have to do is to use parallelStream() instead of stream().</p><p>To see how much impact we can gain from this, let’s look at the following example where we mock the long-taking task as follows:</p><pre>private void longTask() {<br>    // Mock long task.<br>    try {<br>        Thread.sleep(1);<br>    } catch (InterruptedException e) {<br>        throw new RuntimeException(e);<br>    }<br>}</pre><p>Looping through the list will look like this:</p><pre>protected void loop(List&lt;Item&gt; items) {<br>    for (Item item : items) {<br>        longTask();<br>    }<br>}</pre><p>Streams will look like this:</p><pre>protected void stream(List&lt;Item&gt; items) {<br>    items.stream().forEach(item -&gt; longTask());<br>}</pre><p>And finally, parallel streams will look like this:</p><pre>protected void parallel(List&lt;Item&gt; items) {<br>    items.parallelStream().forEach(item -&gt; longTask());<br>}</pre><p>Notice that only stream() has changed to parallelStream().</p><p>Here is the comparison:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cd248a318a34eeb92e35adba5f5304f8/href">https://medium.com/media/cd248a318a34eeb92e35adba5f5304f8/href</a></iframe><p>As expected, loops and Streams show little difference. Then what about parallel streams? Sensational! It’s saving more than 80% of the execution time compared to other implementations! How is this possible?</p><p>Regarding tasks that take a long time to finish and should be done for each element in the list independently, they can run simultaneously, and we can expect significant improvement. This is what parallel streams are doing. They distribute them into multiple threads and make them run simultaneously.</p><p>Parallel streams are only sometimes a winner that you can use everywhere instead of loops or Streams. It is only useful when the tasks are independent. If the tasks are not independent and have to share the same resources, you’ll have to keep them safe with a lock, mainly by synchronized keyword in Java, and make them run slower than normal iterations.</p><h3>Limitations</h3><p>Streams, however, also have limitations. One case is conditional loops, and another one is repetitions. Let’s see what they mean.</p><h4>Conditional loops</h4><p>When we want to repeat until the condition is true but are not sure how many iterations it will take, we normally use the while loop.</p><pre>boolean condition = true;<br>while (condition) {<br>    ...<br>    condition = doSomething();<br>}</pre><p>The code that behaves the same using Streams looks like this:</p><pre>Stream.iterate(true, condition -&gt; condition, condition -&gt; doSomething())<br>        .forEach(unused -&gt; ...);</pre><p>You can see that some boilerplate parts bother the reading, such as condition -&gt; condition that checks whether the condition is true, and unused parameter inside the forEach(). Considering this, conditional loops are better written in while loops.</p><h4>Repetition</h4><p>Repetition is one of the main reasons for the for loop’s existence. Let’s say we want to repeat the process ten times. With the for loop, it can be easily written as:</p><pre>for (int i = 0; i &lt; 10; i++) {<br>  ...<br>}</pre><p>In Streams, one way to achieve this is to make an IntStream that contains [0, 1, 2, ... , 9] and iterate it.</p><pre>IntStream.range(0, 10).forEach(i -&gt; ...);</pre><p>Although the code may look concise and proper, it looks more focused on the values of the range 0 to 10 (exclusive), where the for loop code can be read repeat ten times as it’s more general to write repeat in this way: starting from 0 and ending having the number of repetition times.</p><h3>Summary</h3><p>We’ve gone through some comparisons between Streams and loops. So… can Streams replace loops? Well, as always, it depends on the situation! However, Streams can usually provide you with more concise, easy-to-read code and optimizations.</p><p>So, what are you waiting for? Go ahead and start writing your codes with Streams!</p><p>The codes written for this article can be found on my <a href="https://github.com/CubeDr/medium/tree/master/src/streamloop">GitHub</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f56d4461743a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/can-streams-replace-loops-in-java-f56d4461743a">Can Streams Replace Loops in Java?</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>