{"id":547877,"date":"2025-02-25T13:31:20","date_gmt":"2025-02-25T12:31:20","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=idea&#038;p=547877"},"modified":"2025-03-05T14:28:05","modified_gmt":"2025-03-05T13:28:05","slug":"java-24-build-games-prototypes-utilities-and-more-with-less-boilerplate","status":"publish","type":"idea","link":"https:\/\/blog.jetbrains.com\/ja\/idea\/2025\/02\/java-24-build-games-prototypes-utilities-and-more-with-less-boilerplate","title":{"rendered":"Java 24: Build Games, Prototypes, Utilities, and More \u2013With Less Boilerplate"},"content":{"rendered":"\n<p>At ten, I sat in my school\u2019s computer lab, in awe of a line drawing on the screen \u2013 my own code had brought it to life. <em>\u201cYay! I coded that! I can code anything!\u201d<\/em>, I thought. My teacher, surprised, asked, <em>\u201cWow! You did that?\u201d <\/em>It felt like magic, but it was more than that \u2013 I realized I could turn ideas into reality through code. At that moment, I knew I was going to be a developer.<\/p>\n\n\n\n<p>Now, imagine sparking that same excitement for new Java developers with simple, fun programs (such as games) \u2013 made easier by Java\u2019s modern features that cut boilerplate code. These new features are not just for beginners; experienced developers can write cleaner, faster code for tasks like building prototypes, filtering logs, scraping stock prices, or creating powerful utilities.<\/p>\n\n\n\n<p>Newer features, such as, <a href=\"https:\/\/openjdk.org\/jeps\/495\" target=\"_blank\" rel=\"noopener\">Simple Source Files &amp; Instance Main Methods (JEP 495)<\/a> and <a href=\"https:\/\/openjdk.org\/jeps\/494\" target=\"_blank\" rel=\"noopener\">Module Import Declarations (JEP 494)<\/a> cut down unnecessary complexity. In this blog post, I\u2019ll demonstrate these features through practical use cases. If you\u2019re new to simple source files and instance main methods, check out my <a href=\"https:\/\/blog.jetbrains.com\/idea\/2024\/02\/helloworld-and-main-meet-minimalistic\/\">introductory blog post<\/a> on this topic.&nbsp;<\/p>\n\n\n\n<p>Let\u2019s get started.<\/p>\n\n\n<h2>1. Build Games and create interesting graphics<\/h2>\n\n\n<p>In this section, I\u2019ll talk about building classic games and generating patterns, such as: <\/p>\n\n\n<ul>\n<li><a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\/blob\/master\/src\/ConcentricCirclesDrawOnClick.java\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Drawing Concentric circles<\/span><\/a><span style=\"font-weight: 400;\"> &#8211; A fun animation to watch in action.<\/span><\/li>\n<li><a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\/blob\/master\/src\/HangmanGame.java\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Hangman<\/span><\/a><span style=\"font-weight: 400;\"> &#8211; Guess a word, one letter at a time.<\/span><\/li>\n<li><a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\/blob\/master\/src\/TreasureHunt.java\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Treasure hunt<\/span><\/a><span style=\"font-weight: 400;\"> &#8211; Find the location of the hidden treasure.<\/span><\/li>\n<li><a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\/blob\/master\/src\/RockPaperScissorsSwingUI.java\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Rock-Papper-Scissors<\/span><\/a><span style=\"font-weight: 400;\"> &#8211; Who hasn\u2019t played this classic?<\/span><\/li>\n<li><a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\/blob\/master\/src\/DotsAndBoxes.java\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Dots and Boxes<\/span><\/a><span style=\"font-weight: 400;\"> &#8211; Join lines to complete boxes and claim territory.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">The gif below shows these games and patterns in action. If you like them, feel free to try them out using the source code hosted <\/span><a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">here<\/span><\/a><span style=\"font-weight: 400;\">. I deliberately didn\u2019t include the full source code for all these games in this blog post, as it\u2019s quite lengthy and could distract from the main point I\u2019m trying to make.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">I\u2019ve included these games to highlight how easy it is to get started with Java\u2014and how you can build games like these and much more.<\/span><\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-549251\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/02\/games2.gif\" alt=\"\" width=\"2496\" height=\"1812\" \/><\/p>\n\n\n<p>Some of these games are terminal-based, such as Hangman and Treasure Hunt (implicit classes), while others have a Swing-based UI (regular classes). If you ask me, my favorite game during my growing-up years was Dots and Boxes \u2013 I have fond memories of playing it with my friends at school in a notebook.<\/p>\n\n\n\n<p>The codebase of these games demonstrates that implicit classes and instance main methods can be used not just to get started but also to build much more complex applications. These classes aren\u2019t overly simple; they include sophisticated algorithm implementations using control flow statements.<\/p>\n\n\n\n<p>Speaking of algorithms, I don\u2019t think the code for the Dots and Boxes game currently implements a strong algorithm for the computer opponent. I\u2019m accepting pull requests if you\u2019d like to try improving it \u2013 the game is hosted <a href=\"https:\/\/github.com\/malagupta\/HelloWorldProjJava24\/blob\/master\/src\/DotsAndBoxes.java\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n\n\n<h2>2. Processing log files<\/h2>\n\n\n<p>Imagine you need to extract error messages (containing the text \u2018ERROR\u2019) from a log file and save them to a separate file for later review. Here\u2019s a section of the log file, with the target lines highlighted:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/02\/log-file.png\" alt=\"\" class=\"wp-image-16062\"\/><\/figure>\n\n\n\n<p>You could accomplish this task by using (just) the following executable code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void main() throws IOException {\n    List&lt;String> errors = Files.readAllLines(Path.of(\"src\/main\/logs\/app.log\"))\n                               .stream()\n                               .filter(line -> line.contains(\"ERROR\"))\n                               .collect(Collectors.toList());\n    Files.write(Path.of(\"src\/main\/logs\/error.log\"), errors);\n}<\/pre>\n\n\n\n<p>The following gif shows the contents of app.log, execution of the preceding code in IntelliJ IDEA (<em>.java<\/em> file without declaration of a class) and the contents of the newly created file, that is, errors.log:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/02\/log-file.gif\" alt=\"\" class=\"wp-image-16062\"\/><\/figure>\n\n\n\n<p>Reading a file, filtering its contents, and creating another file\u2014all with just a few lines of code. Isn\u2019t that great? This example reads a <em>.log<\/em> file, but you could easily adapt it to read other formats, such as <em>.csv<\/em>, <em>.json<\/em>, and more.<\/p>\n\n\n\n<p>The next section covers what happens behind the scenes and why. If you&#8217;re already familiar with these details, feel free to skip ahead to the next practical example.<\/p>\n\n\n<h3>Behind the scenes<\/h3>\n\n\n<p>As a developer, the code shown in the previous section offers multiple benefits:<\/p>\n\n\n\n<ul>\n<li>You can focus on the logic of reading app.log and creating error.log.<\/li>\n\n\n\n<li>You no longer need to create an explicit enclosing class to execute this code. It is automatically defined in an implicit class (similar to how a default package works).<\/li>\n\n\n\n<li>The signature of the implicit main method is shorter.<\/li>\n\n\n\n<li>You don&#8217;t need to write explicit import statements for Java I\/O classes. This also applies to all classes or interfaces from the java.base module, as an implicit class automatically imports any package exported by java.base (on demand).<\/li>\n\n\n\n<li>Overall, the code is shorter, making it easier to read and write.&nbsp;<\/li>\n<\/ul>\n\n\n\n<p>If you prefer command prompt, you could also avail the benefits of skipping compilation of this class and execute the code using the command <em>java &lt;name of your source file><\/em>. If you are using your favorite IDE, such as IntelliJ IDEA, you can execute your code using a single click by using the Run feature (by either using the icon or the related shortcut).<\/p>\n\n\n\n<p>Are you wondering how the code will change without these newer Java features-implicit class, instance main method, and module import declaration). IntelliJ IDEA includes context actions to convert an implicit class to a regular class and vice versa.&nbsp;<\/p>\n\n\n\n<p>The following gif shows what happens when you convert the preceding code implicit class to a regular class by using the context action \u2018Convert implicitly declared class into a regular class\u2019 on method main():<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"2481\" height=\"1812\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/02\/convert-reg-class-module.gif\" alt=\"\" class=\"wp-image-549275\"\/><\/figure>\n\n\n\n<p>You might wonder how significant these changes are and why you would even want to convert an implicit class to a regular class. Converting an implicit class to a regular class makes sense when you&#8217;re ready to work with classes more formally, integrate the code into another project, or package it for reuse.<\/p>\n\n\n\n<p>The conversion might not seem like a big change at first, especially since it imports the java.base module by default, instead of importing individual classes or interfaces from packages like io, nio, or util, as shown below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.List;\nimport java.util.stream.Collectors;\n<\/pre>\n\n\n\n<p>The module java.base is automatically imported in implicit classes, so they don\u2019t need import statements for using the classes and interfaces mentioned in the preceding code. Just in case you are curious to find out which modules are exported by the module java.base, you could access that information by navigating to its declaration, as shown in the following gif:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"2496\" height=\"1812\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/02\/java-base-mod.gif\" alt=\"\" class=\"wp-image-549297\"\/><\/figure>\n\n\n\n<p>Importing a single module vc. Loading individual classes and interfaces also lowers the cognitive load when you are reading and writing your code.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Building utilities, such as a Stock Price Scraper<\/h2>\n\n\n\n<p>Imagine you need to look up some stock prices. You could access a website to do so, or, you could also spin up a single method (defined in an implicit class) to do that, as follows:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\n\nvoid main() throws IOException {\n    Document doc = Jsoup.connect(\"https:\/\/finance.yahoo.com\/quote\/AAPL\")\n                        .get();\n    String stockPrice = doc.select(\".price\").text();\n    println(\"Stock Price: \" + stockPrice);\n}\n<\/pre>\n\n\n\n<p>Here\u2019s the output of executing this code snippet:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"2496\" height=\"1812\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/02\/stock-prices.gif\" alt=\"\" class=\"wp-image-549322\"\/><\/figure>\n\n\n\n<p>I created an additional method in the same source file to format the text received from the pinging the website:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public static String formatAndDisplayStockPrice(String stockPrice) {\n    if (stockPrice == null || stockPrice.isEmpty()) {\n        System.out.println(\"No stock price data available.\");\n        return null;\n    }\n    String[] parts = stockPrice.split(\"\\\\s+\");\n    StringBuilder formattedOutput = new StringBuilder();\n    try {\n        formattedOutput.append(String.format(\"\"\"\n            ---------- Stock Price Information ----------\n            Stock Price (At close): %s\n            Change: %s (%s%%)\n            Closing Time: %s %s %s %s\n            After Hours Price: %s\n            Change (After hours): %s (%s)\n            After Hours Time: %s %s %s\n            ----------- Additional Information -----------\n            \"\"\", parts[2], parts[3], parts[4], parts[6], parts[7], parts[8],\n                 parts[9], parts[10], parts[11], parts[12], parts[14], parts[15], parts[16]));\n        for (int i = 17; i < parts.length; i++) {\n            formattedOutput.append(String.format(\"Metric %d: %s%n\", (i - 16), parts[i]));\n        }\n    } catch (ArrayIndexOutOfBoundsException e) {\n        System.out.println(\"Unexpected format in stock price data. Raw data: \" + stockPrice);\n    }\n    return formattedOutput.toString();\n}\n<\/pre>\n\n\n\n<p>To enable your runtime to find the classes imported from the packages <em>org.jsoup<\/em> and <em>org.jsoup.nodes<\/em>, you can either add them to your <em>classpath<\/em> or include them as dependencies in your Maven or Gradle build configuration.<\/p>\n\n\n\n<p>The examples shown in this blog post are just the tip of the iceberg \u2013 you can create many other utilities using these features.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Summary<\/strong><\/h2>\n\n\n\n<p>Newer features in Java 24, such as, <a href=\"https:\/\/openjdk.org\/jeps\/495\" target=\"_blank\" rel=\"noopener\">Simple Source Files &amp; Instance Main Methods (JEP 495)<\/a> and <a href=\"https:\/\/openjdk.org\/jeps\/494\" target=\"_blank\" rel=\"noopener\">Module Import Declarations (JEP 494)<\/a> aren't just about cutting down boilerplate code. They also reduce the cognitive load of getting started with Java, making it easier to dive into coding \u2013 whether you're creating fun games, building practical scripts, or developing prototypes and utilities faster.<\/p>\n\n\n\n<p>If you haven\u2019t tried these features yet, you\u2019re missing out on a lot of fun!<\/p>\n","protected":false},"author":921,"featured_media":549387,"comment_status":"closed","ping_status":"closed","template":"","categories":[4759],"tags":[8708,155,8706],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/547877"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/types\/idea"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/users\/921"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/comments?post=547877"}],"version-history":[{"count":9,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/547877\/revisions"}],"predecessor-version":[{"id":551229,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/idea\/547877\/revisions\/551229"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/media\/549387"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/media?parent=547877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/categories?post=547877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/tags?post=547877"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/ja\/wp-json\/wp\/v2\/cross-post-tag?post=547877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}