Welcome to the first chapter of our comprehensive Java development journey! In this chapter, we will lay the essential groundwork for all subsequent projects by setting up a robust, production-ready Java 25 development environment. This foundational step is crucial as it ensures you have all the necessary tools and configurations in place to write, build, test, and deploy modern Java applications efficiently and effectively.

By the end of this chapter, you will have a fully configured development machine equipped with the latest Java Development Kit (JDK 25), Apache Maven for project management, and a powerful Integrated Development Environment (IDE). We will also create a minimal “Hello, World!” project, incorporating essential production considerations like structured logging and unit testing, to verify our setup. This hands-on approach will not only get your environment ready but also introduce you to best practices from the very beginning.

Planning & Design

For setting up a development environment, the “planning and design” phase focuses on selecting the right tools and understanding their roles. There isn’t an application architecture to design at this stage, but rather a toolchain architecture.

Toolchain Architecture:

  • Java Development Kit (JDK 25): The core component. It includes the Java Runtime Environment (JRE) for running Java applications and development tools (like the compiler javac) for creating them. We will use OpenJDK 25, the open-source reference implementation, which is highly recommended for its performance, stability, and community support. The search results indicate Java 25 is the latest stable version as of December 2025.
  • Apache Maven: Our chosen build automation tool. Maven will manage project dependencies, compile code, run tests, package applications, and handle the entire build lifecycle. Its convention-over-configuration approach simplifies project setup and maintenance, making it an industry standard for Java projects.
  • Integrated Development Environment (IDE): A powerful software application that provides comprehensive facilities to computer programmers for software development. We will use IntelliJ IDEA Community Edition, renowned for its intelligent code assistance, robust debugging tools, and seamless integration with Maven and Java.
  • Version Control System (Git): While not explicitly installed in this chapter, Git is a fundamental tool for any development project. We assume you have Git installed and are familiar with basic commands. If not, please install Git from git-scm.com before proceeding.

Step-by-Step Implementation

Let’s begin by installing and configuring our development tools.

a) Setup/Configuration: Install Java Development Kit (JDK 25)

The JDK is the heart of Java development. It provides everything you need to compile and run Java code. We’ll use SDKMAN! (Software Development Kit Manager) for a streamlined installation experience, as it allows easy switching between different JDK versions.

1. Install SDKMAN! (Recommended)

SDKMAN! is a command-line tool for managing parallel versions of multiple SDKs on most Unix-like systems. If you’re on Windows, you can use WSL (Windows Subsystem for Linux) or install directly.

  • Open your terminal (macOS/Linux) or WSL terminal (Windows) and run:
    curl -s "https://get.sdkman.io" | bash
    
  • Follow the on-screen instructions. You might need to close and reopen your terminal or source the initialization script:
    source "$HOME/.sdkman/bin/sdkman-init.sh"
    
  • Verify SDKMAN! installation:
    sdk version
    
    You should see the SDKMAN! version.

2. Install OpenJDK 25 using SDKMAN!

Now, let’s install the latest OpenJDK 25.

  • List available Java versions:
    sdk list java
    
    Look for a version labeled 25.x.x-tem or similar, indicating a recent release of OpenJDK 25. As of December 2025, the latest release might be something like 25.0.1-tem. We will assume 25.0.1-tem for this guide.
  • Install OpenJDK 25:
    sdk install java 25.0.1-tem # Replace with the actual latest 25.x.x version from 'sdk list java'
    
    SDKMAN! will download and install the specified JDK. It will also set it as your default Java version.

3. Verify Java Installation

It’s crucial to verify that Java 25 is correctly installed and configured in your system’s PATH.

  • Check Java runtime version:
    java --version
    
    Expected output should show openjdk 25.x.x
    openjdk 25.0.1 2025-09-17
    OpenJDK Runtime Environment Temurin-25.0.1+1 (build 25.0.1+1)
    OpenJDK 64-Bit Server VM Temurin-25.0.1+1 (build 25.0.1+1, mixed mode, sharing)
    
  • Check Java compiler version:
    javac --version
    
    Expected output should show javac 25.x.x
    javac 25.0.1
    

4. Set JAVA_HOME Environment Variable (If not automatically set by SDKMAN!)

While SDKMAN! usually handles this, it’s good practice to ensure JAVA_HOME is correctly set, as many tools rely on it.

  • Find your Java installation path:
    sdk home java
    
    This will output the path, e.g., /home/youruser/.sdkman/candidates/java/25.0.1-tem
  • Add to your shell profile (e.g., ~/.bashrc, ~/.zshrc, or ~/.profile):
    # Open your shell profile file
    nano ~/.zshrc # or ~/.bashrc, ~/.profile
    
    # Add these lines at the end:
    export JAVA_HOME=$(sdk home java)
    export PATH="$JAVA_HOME/bin:$PATH"
    
    # Save and exit (Ctrl+X, Y, Enter for nano)
    
  • Apply changes:
    source ~/.zshrc # or ~/.bashrc, ~/.profile
    
  • Verify JAVA_HOME:
    echo $JAVA_HOME
    
    This should output the path to your JDK 25 installation.

b) Setup/Configuration: Install Apache Maven

Maven is our project build tool. It manages dependencies, compiles code, runs tests, and packages our applications.

1. Install Maven using SDKMAN! (Recommended)

  • Install Maven:
    sdk install maven
    
  • Verify Maven installation:
    mvn --version
    
    Expected output:
    Apache Maven 3.9.6 (XXXXXX; 2023-12-18T16:04:09+00:00)
    Maven home: /home/youruser/.sdkman/candidates/maven/current
    Java version: 25.0.1, vendor: Eclipse Adoptium, runtime: /home/youruser/.sdkman/candidates/java/25.0.1-tem
    Default locale: en_US, platform encoding: UTF-8
    OS name: "linux", version: "6.5.0-14-generic", arch: "amd64", family: "unix"
    
    Ensure Java version shows 25.x.x.

c) Setup/Configuration: Install an Integrated Development Environment (IDE)

An IDE significantly boosts productivity. IntelliJ IDEA is an excellent choice for Java.

1. Install IntelliJ IDEA Community Edition

  • Download: Go to the official JetBrains website: https://www.jetbrains.com/idea/download/
  • Select “Community” edition for your operating system (Windows, macOS, Linux).
  • Follow the installation instructions for your OS. This usually involves running an installer or extracting an archive.

2. Initial IntelliJ IDEA Setup

  • Launch IntelliJ IDEA.
  • On the welcome screen, select “New Project”.
  • Ensure your JDK 25 is recognized. In the “New Project” dialog, under “JDK”, it should automatically detect your SDKMAN! installed Java 25. If not, click “Add JDK” -> “Add SDK” -> “JDK” and navigate to your JAVA_HOME path (e.g., /home/youruser/.sdkman/candidates/java/25.0.1-tem).
  • Ensure Maven is recognized. IntelliJ IDEA typically detects Maven if it’s in your PATH. You can verify this in File -> Settings (Windows/Linux) or IntelliJ IDEA -> Settings (macOS) -> Build, Execution, Deployment -> Build Tools -> Maven. The “Maven home directory” should point to your SDKMAN! Maven installation (e.g., /home/youruser/.sdkman/candidates/maven/current).

d) Core Implementation: Create a Basic “Hello, World!” Maven Project

Now that our tools are installed, let’s create our first project to verify everything works together.

1. Create the Project Structure using Maven Archetype

Open your terminal and navigate to your desired projects directory.

cd ~/dev/java-projects # Or any directory you prefer

Now, use Maven to generate a basic project.

mvn archetype:generate \
    -DgroupId=com.example.app \
    -DartifactId=hello-java25 \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.4 \
    -DinteractiveMode=false
  • groupId: Unique identifier for your organization/project.
  • artifactId: Unique name for the project’s JAR without version.
  • maven-archetype-quickstart: A basic Maven project template.
  • interactiveMode=false: Skips interactive prompts.

This command creates a directory hello-java25 with the following structure:

hello-java25/
├── pom.xml
└── src/
    ├── main/
    │   └── java/
    │       └── com/
    │           └── example/
    │               └── app/
    │                   └── App.java
    └── test/
        └── java/
            └── com/
                └── example/
                    └── app/
                        └── AppTest.java

2. Import Project into IntelliJ IDEA

  • In IntelliJ IDEA, go to File -> Open...
  • Navigate to the hello-java25 directory and select the pom.xml file.
  • Choose “Open as Project”. IntelliJ will import the Maven project, download dependencies, and set up the project structure.

3. Configure pom.xml for Java 25

The maven-archetype-quickstart typically defaults to an older Java version. We need to explicitly configure it for Java 25.

File: hello-java25/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.app</groupId>
    <artifactId>hello-java25</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>25</maven.compiler.source> <!-- Set Java source version to 25 -->
        <maven.compiler.target>25</maven.compiler.target> <!-- Set Java target version to 25 -->
        <junit.version>5.10.0</junit.version> <!-- Use latest JUnit 5 -->
        <slf4j.version>2.0.11</slf4j.version> <!-- Use latest SLF4J 2.x -->
        <logback.version>1.4.14</logback.version> <!-- Use latest Logback 1.4.x -->
    </properties>

    <dependencies>
        <!-- JUnit 5 for testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Logging dependencies: SLF4J API and Logback implementation -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version> <!-- Ensure a recent compiler plugin -->
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.2</version> <!-- Ensure a recent Surefire plugin for JUnit 5 -->
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.1.0</version> <!-- Plugin to run main class easily -->
                <configuration>
                    <mainClass>com.example.app.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • Explanation:
    • We’ve added maven.compiler.source and maven.compiler.target properties to 25 to instruct Maven to compile our code against Java 25.
    • We updated junit.version to 5.10.0 for JUnit 5.
    • We added slf4j.version and logback.version properties for centralized dependency management.
    • Crucially, we added dependencies for SLF4J API and Logback Classic. These are industry standards for flexible and robust logging.
    • We ensured maven-compiler-plugin and maven-surefire-plugin are recent versions to support Java 25 and JUnit 5 respectively.
    • The exec-maven-plugin is added to easily run the main class from the command line.

After modifying pom.xml, IntelliJ IDEA will prompt you to “Load Maven Changes” or similar. Click on it to download the new dependencies.

4. Modify App.java

Let’s update the default App.java to use Java 25 features (like text blocks, if desired, though not strictly necessary for “Hello World”) and introduce our logging framework.

File: hello-java25/src/main/java/com/example/app/App.java

package com.example.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A simple "Hello, World!" application demonstrating Java 25 environment setup
 * with Maven, SLF4J/Logback, and basic error handling.
 */
public class App {
    // Initialize a logger instance for this class.
    // This is a standard practice for logging in production applications.
    private static final Logger logger = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        // Log a greeting message at INFO level.
        // Using parameterized logging ({}) for performance and to avoid string concatenation issues.
        logger.info("Application starting...");
        try {
            String greeting = getGreeting();
            logger.info("Greeting: {}", greeting);
            System.out.println(greeting); // Also print to console for immediate visibility

            // Simulate a potential error condition
            if (args.length > 0 && "error".equalsIgnoreCase(args[0])) {
                throw new IllegalArgumentException("Simulated error from command line argument.");
            }

            logger.info("Application finished successfully.");
        } catch (Exception e) {
            // Log any unexpected exceptions at ERROR level, including the stack trace.
            // This is vital for debugging in production.
            logger.error("An unexpected error occurred during application execution: {}", e.getMessage(), e);
            // Exit with a non-zero status code to indicate failure
            System.exit(1);
        }
    }

    /**
     * Returns a simple greeting string.
     * @return The greeting message.
     */
    public static String getGreeting() {
        // Example of a simple Java method.
        // In a real application, this might fetch data, perform calculations, etc.
        return "Hello, Java 25 World!";
    }
}
  • Explanation:
    • We import org.slf4j.Logger and org.slf4j.LoggerFactory to integrate our logging framework.
    • A private static final Logger instance is created, which is the standard way to get a logger for a class.
    • We use logger.info() instead of System.out.println() for application messages. This allows us to control log levels, destinations, and formats.
    • Parameterized logging (logger.info("Greeting: {}", greeting);) is used for efficiency and to prevent potential security issues with string concatenation.
    • A basic try-catch block is added to demonstrate robust error handling. Any Exception is caught, logged at ERROR level with its stack trace, and the application exits with a non-zero status code, signaling a failure to calling scripts or CI/CD pipelines.
    • A getGreeting() method is introduced to represent a simple business logic component that can be tested.

e) Core Implementation: Configure Logging (SLF4J + Logback)

For logging to work, Logback needs a configuration file.

1. Create logback.xml

Create a new directory resources under src/main and then create the logback.xml file inside it.

File: hello-java25/src/main/resources/logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- Console Appender: For development, logs to standard output -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- Pattern for console output: timestamp, log level, thread, logger name, message, new line -->
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- File Appender: For production, logs to a file -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/hello-java25.log</file> <!-- Log file name -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- Daily rollover: logs/hello-java25.2025-12-04.log -->
            <fileNamePattern>logs/hello-java25.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- Keep 30 days of history -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <!-- Pattern for file output: more detailed, includes full timestamp -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- Root logger configuration -->
    <root level="info"> <!-- Default log level for the application -->
        <appender-ref ref="CONSOLE" /> <!-- Send logs to console -->
        <appender-ref ref="FILE" />    <!-- Send logs to file -->
    </root>

    <!-- Specific logger for a package or class (optional) -->
    <!-- Example: Set debug level for a specific package -->
    <!-- <logger name="com.example.app.SomeSpecificClass" level="debug" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger> -->

</configuration>
  • Explanation:
    • This logback.xml sets up two appenders: CONSOLE for immediate feedback during development and FILE for persistent logging in production.
    • The FILE appender uses RollingFileAppender with TimeBasedRollingPolicy to create daily log files and retain them for 30 days, which is a common production best practice.
    • The root logger is configured to output INFO level messages (and higher: WARN, ERROR) to both the console and the file.
    • Different pattern elements are used for console and file logs, typically file logs are more verbose.

f) Core Implementation: Simple Unit Test (JUnit 5)

Writing tests is an integral part of building production-ready software. Let’s create a simple unit test for our App class.

1. Modify AppTest.java

File: hello-java25/src/test/java/com/example/app/AppTest.java

package com.example.app;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
 * Unit test for the App class.
 * Demonstrates basic testing with JUnit 5.
 */
class AppTest {

    @Test
    @DisplayName("Should return the correct greeting message")
    void getGreetingShouldReturnCorrectMessage() {
        // Arrange - No specific setup needed for a static method call
        String expectedGreeting = "Hello, Java 25 World!";

        // Act - Call the method under test
        String actualGreeting = App.getGreeting();

        // Assert - Verify the outcome
        assertNotNull(actualGreeting, "Greeting should not be null");
        assertEquals(expectedGreeting, actualGreeting, "The greeting message should match the expected value.");
    }

    @Test
    @DisplayName("Should instantiate App class successfully")
    void appClassShouldInstantiate() {
        // Arrange & Act
        App app = new App();

        // Assert
        assertNotNull(app, "App instance should not be null");
    }
}
  • Explanation:
    • We use JUnit 5 annotations like @Test and @DisplayName.
    • getGreetingShouldReturnCorrectMessage tests the getGreeting() method from App.java, asserting that it returns the expected string and is not null.
    • appClassShouldInstantiate is a simple test to ensure the App class can be instantiated, which can be useful for classes with constructors or initializers.
    • The test follows the Arrange-Act-Assert pattern for clarity.

g) Testing This Component

With our project set up, App.java modified, logging configured, and a test written, let’s test it out.

1. Build the Project

Open your terminal in the hello-java25 directory.

cd ~/dev/java-projects/hello-java25
mvn clean install
  • mvn clean: Cleans the target directory.
  • mvn install: Compiles the source code, runs tests, and packages the compiled code into a JAR file, installing it into your local Maven repository.

Expected output will show BUILD SUCCESS and indicate that tests were run.

2. Run the Application

mvn exec:java

Expected console output:

... (Logback initialization messages) ...
HH:mm:ss.SSS [main] INFO  com.example.app.App - Application starting...
HH:mm:ss.SSS [main] INFO  com.example.app.App - Greeting: Hello, Java 25 World!
Hello, Java 25 World!
HH:mm:ss.SSS [main] INFO  com.example.app.App - Application finished successfully.
...

Also, check the logs directory created in hello-java25. You should find a hello-java25.YYYY-MM-DD.log file containing the same log messages.

3. Test Error Handling

Let’s simulate the error condition we added.

mvn exec:java -Dexec.args="error"

Expected console output:

... (Logback initialization messages) ...
HH:mm:ss.SSS [main] INFO  com.example.app.App - Application starting...
HH:mm:ss.SSS [main] INFO  com.example.app.App - Greeting: Hello, Java 25 World!
Hello, Java 25 World!
HH:mm:ss.SSS [main] ERROR com.example.app.App - An unexpected error occurred during application execution: Simulated error from command line argument.
... (full stack trace) ...

The application will exit with status 1 and the error will be logged to the console and the log file.

4. Run Unit Tests

mvn test

Expected output will show BUILD SUCCESS and indicate that 2 tests ran successfully.

Debugging Tips:

  • Maven Errors: If mvn clean install fails, read the error messages carefully. They often point to missing dependencies, compilation issues, or incorrect pom.xml configurations.
  • Java Version Mismatch: If you get Unsupported class file major version errors, double-check your pom.xml’s maven.compiler.source/target and ensure your java --version output is correct.
  • IDE Issues: If IntelliJ IDEA shows red errors or can’t resolve symbols, try File -> Invalidate Caches / Restart... and then “Load Maven Changes” again. Ensure the correct JDK is selected in File -> Project Structure -> Project SDK.
  • Logging Not Working: Verify logback.xml is in src/main/resources. Check for typos in the XML. Ensure slf4j-api and logback-classic dependencies are present in pom.xml.

Production Considerations

Even for a simple environment setup, thinking about production is key.

  • JDK Updates (Critical Patch Updates - CPUs): The search results show Oracle provides Critical Patch Updates (CPUs) for Java SE regularly (e.g., April, July 2025). It is paramount to keep your JDK updated, especially in production environments, to incorporate the latest security fixes and performance improvements. Automate this process in your CI/CD pipelines.
  • Logging Configuration: The logback.xml provided is a good starting point. In production, you might configure different appenders (e.g., to a centralized log management system like ELK stack, Splunk, or cloud-native logging services), control log levels per environment (e.g., WARN or ERROR in production, DEBUG in development), and implement more sophisticated rolling policies (e.g., by size, compression).
  • Dependency Management: Maven’s pom.xml allows for precise control over dependencies. Always specify exact versions for production dependencies to ensure reproducible builds. Consider using Maven Enforcer Plugin to enforce dependency constraints and check for vulnerabilities.
  • Security:
    • Least Privilege: Ensure your application runs with the minimum necessary permissions in production.
    • Secure Coding Practices: While not directly applicable to environment setup, always prioritize secure coding practices for your applications from day one.
    • Dependency Scanning: Integrate tools like OWASP Dependency-Check or Snyk into your CI/CD pipeline to scan for known vulnerabilities in your project’s dependencies.

Code Review Checkpoint

At this point, you have successfully:

  • Installed OpenJDK 25 using SDKMAN!.
  • Installed Apache Maven using SDKMAN!.
  • Installed and configured IntelliJ IDEA.
  • Created a new Maven project (hello-java25).
  • Configured pom.xml for Java 25, including dependencies for SLF4J/Logback and JUnit 5.
  • Modified App.java to include a simple method, use SLF4J for logging, and implement basic error handling.
  • Created logback.xml for structured logging with console and file appenders.
  • Written a unit test AppTest.java using JUnit 5.
  • Successfully built, run, and tested the application, including its error handling and unit tests.

The key files created/modified are:

  • hello-java25/pom.xml
  • hello-java25/src/main/java/com/example/app/App.java
  • hello-java25/src/main/resources/logback.xml
  • hello-java25/src/test/java/com/example/app/AppTest.java

This setup provides a solid, production-ready foundation for all future projects.

Common Issues & Solutions

  1. Issue: java: release version 25 not supported or javac: invalid target release: 25

    • Cause: Your maven-compiler-plugin or the JDK configured in your IDE is not actually Java 25, or the compiler plugin is too old to recognize Java 25.
    • Solution:
      • Verify java --version and javac --version both show 25.x.x. If not, re-run sdk install java 25.0.1-tem and sdk default java 25.0.1-tem.
      • Ensure maven.compiler.source and maven.compiler.target in pom.xml are set to 25.
      • Update maven-compiler-plugin version in pom.xml to 3.11.0 or newer.
      • In IntelliJ IDEA, go to File -> Project Structure -> Project and ensure “Project SDK” is set to your Java 25 JDK. Also check File -> Project Structure -> Modules -> Sources tab, ensure “Language level” is “25 - New features since Java 24”.
  2. Issue: mvn command not found

    • Cause: Maven is not correctly installed or not added to your system’s PATH.
    • Solution:
      • If using SDKMAN!, ensure you ran sdk install maven and sdk default maven.
      • If installing manually, ensure the Maven bin directory is added to your system’s PATH environment variable. After modifying PATH, remember to source your shell profile or open a new terminal.
  3. Issue: Error: Could not find or load main class com.example.app.App when running mvn exec:java

    • Cause: The mainClass configured in exec-maven-plugin in pom.xml is incorrect, or the App.java file is not in the expected package path.
    • Solution:
      • Double-check the mainClass property in pom.xml to ensure it exactly matches the fully qualified name of your App class (e.g., com.example.app.App).
      • Verify that App.java is located at src/main/java/com/example/app/App.java.
      • Run mvn clean install first to ensure the project compiles correctly and the .class files are generated.

Testing & Verification

To confirm your development environment is fully operational and configured for production-ready development:

  1. Verify Java Version:

    java --version
    javac --version
    

    Both should output 25.x.x.

  2. Verify Maven Version:

    mvn --version
    

    This should show Maven version (e.g., 3.9.6) and also confirm it’s using Java version: 25.x.x.

  3. Run the “Hello, Java 25 World!” Application:

    cd ~/dev/java-projects/hello-java25
    mvn clean install
    mvn exec:java
    

    Confirm you see “Hello, Java 25 World!” printed to the console and the log messages in the logs/hello-java25.YYYY-MM-DD.log file.

  4. Test Error Handling:

    mvn exec:java -Dexec.args="error"
    

    Confirm an error message and stack trace are logged, and the application exits with a non-zero status.

  5. Run Unit Tests:

    mvn test
    

    Confirm all tests pass (Tests run: 2, Failures: 0, Errors: 0, Skipped: 0).

If all these steps pass successfully, your Java 25 development environment is perfectly set up and ready for building real-world applications!

Summary & Next Steps

Congratulations! You have successfully set up a modern Java 25 development environment, complete with JDK 25, Maven, IntelliJ IDEA, structured logging, and unit testing. This chapter has equipped you with the foundational tools and best practices required for building robust and maintainable Java applications. You now have a working “Hello, Java 25 World!” project that serves as a template for future development.

In the next chapter, we will dive into building our first project: a Simple Calculator. We will leverage the environment we just configured to start writing practical Java code, focusing on object-oriented design, user input handling, and further refining our testing and logging practices. Get ready to build something tangible!