<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Noel KAMPHOA</title>
    <description>The latest articles on DEV Community by Noel KAMPHOA (@noel_kamphoa_e688aece0725).</description>
    <link>https://dev.to/noel_kamphoa_e688aece0725</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3161637%2Fb2566b75-d6f0-4301-b327-1c68daed6de7.jpg</url>
      <title>DEV Community: Noel KAMPHOA</title>
      <link>https://dev.to/noel_kamphoa_e688aece0725</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noel_kamphoa_e688aece0725"/>
    <language>en</language>
    <item>
      <title>Centralized Logging for Java Apps With ELK and Docker Compose</title>
      <dc:creator>Noel KAMPHOA</dc:creator>
      <pubDate>Sat, 23 Aug 2025 20:58:49 +0000</pubDate>
      <link>https://dev.to/noel_kamphoa_e688aece0725/centralized-logging-for-java-apps-with-elk-and-docker-compose-554k</link>
      <guid>https://dev.to/noel_kamphoa_e688aece0725/centralized-logging-for-java-apps-with-elk-and-docker-compose-554k</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;Debugging a distributed Java application by SSH-ing into individual servers to grep through log files is a nightmare. What if you could search and visualize all your Spring Boot logs from a single, powerful dashboard? In this tutorial, we’ll walk through installing the ELK Stack (Elasticsearch, Logstash, Kibana) using Docker Compose—a perfect setup for development and testing. Then, most importantly, I'll show you exactly how to configure your Java application to send its logs straight to ELK. We will be installing the ELK Stack version 8.14.3.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Basic Knowledge of Docker and Docker Compose. This tutorial uses &lt;a href="https://docs.docker.com/desktop/install/windows-install/" rel="noopener noreferrer"&gt;Docker Desktop for Windows&lt;/a&gt;, but you can use any other &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;Docker installation&lt;/a&gt; depending on your Operating System. &lt;/li&gt;
&lt;li&gt;A running Docker and Docker Compose installation on your workstation.&lt;/li&gt;
&lt;li&gt;A Java Application that you want to monitor. You may use this &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/spring-boot/spring-boot-rest" rel="noopener noreferrer"&gt;Spring Boot REST Application&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Directory Structure
&lt;/h2&gt;

&lt;p&gt;First things first. Let's start by creating a directory where we will keep the configuration files of the three services(Elasticsearch, Logstash, Kibana) and the docker-compose.yml file. We will name that directory "elk".&lt;/p&gt;

&lt;p&gt;Below is the directory structure of "elk":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;C:\apps\elk&amp;gt;&lt;/span&gt;tree /f
&lt;span class="go"&gt;Folder PATH listing for volume Windows
Volume serial number is XXX-XXXX
C:.
│   docker-compose.yml
│
├───elasticsearch
│   └───config
│           elasticsearch.yml
│
├───kibana
│   └───config
│           kibana.yml
│
└───logstash
    ├───config
    │       logstash.yml
    │
    ├───pipeline
    │       logstash.conf
    │
    └───sample-logs
            access_log.log
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you create all these files and put them in the exact location under the "elk" directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Configuration files
&lt;/h2&gt;

&lt;p&gt;Fill the configuration files of each of the three services with the content given below. We won't go deeper into the configurations themselves. You can refer to these tutorials to understand more about each service configuration: &lt;a href="https://nkamphoa.com/install-elasticsearch-with-docker/" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt;, &lt;a href="https://nkamphoa.com/install-logstash-with-docker/" rel="noopener noreferrer"&gt;Logstash&lt;/a&gt;, and &lt;a href="https://nkamphoa.com/install-kibana-with-docker/" rel="noopener noreferrer"&gt;Kibana&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1. Elasticsearch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Elasticsearch configuration file&lt;/span&gt;
&lt;span class="c1"&gt;# elasticsearch.yml&lt;/span&gt;
&lt;span class="na"&gt;cluster.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docker-cluster"&lt;/span&gt;
&lt;span class="na"&gt;network.host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2. Logstash
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pipeline&lt;/strong&gt;&lt;br&gt;
We are configuring an &lt;a href="https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html" rel="noopener noreferrer"&gt;input of type file&lt;/a&gt;. Logstash will output its data to Elasticsearch. We also print the data to the console for debugging purposes.&lt;br&gt;
The file path refers to our application logs inside the container. We will &lt;strong&gt;bind that path to the application logs path outside the container&lt;/strong&gt; in the Docker Compose file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Logstash configuration file logstash.conf&lt;/span&gt;
&lt;span class="s"&gt;input{&lt;/span&gt;
    &lt;span class="s"&gt;file {&lt;/span&gt;
        &lt;span class="s"&gt;path =&amp;gt; "/usr/share/logstash/logs/*.log"&lt;/span&gt; &lt;span class="c1"&gt;# Path inside the container&lt;/span&gt;
        &lt;span class="s"&gt;start_position =&amp;gt; "beginning"&lt;/span&gt;
        &lt;span class="s"&gt;sincedb_path =&amp;gt; "/dev/null"&lt;/span&gt;             &lt;span class="c1"&gt;# Optional: for testing, read from start every time&lt;/span&gt;
        &lt;span class="s"&gt;codec =&amp;gt; multiline {&lt;/span&gt;                    &lt;span class="c1"&gt;# CRITICAL for Java stack traces&lt;/span&gt;
          &lt;span class="s"&gt;pattern =&amp;gt; "^%{TIMESTAMP_ISO8601} "&lt;/span&gt;
          &lt;span class="s"&gt;negate =&amp;gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="s"&gt;what =&amp;gt; "previous"&lt;/span&gt;
        &lt;span class="s"&gt;}&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="s"&gt;filter {&lt;/span&gt;
   &lt;span class="s"&gt;# Normalize CRLF&lt;/span&gt;
  &lt;span class="s"&gt;mutate { gsub =&amp;gt; ["message", "\r$", ""] }&lt;/span&gt;

  &lt;span class="s"&gt;grok {&lt;/span&gt;
    &lt;span class="s"&gt;match =&amp;gt; {&lt;/span&gt;
      &lt;span class="s"&gt;"message" =&amp;gt; [&lt;/span&gt;
        &lt;span class="s"&gt;"^%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:level}\s+--- \[(?&amp;lt;thread&amp;gt;[^\]]+)\]\s+%{JAVACLASS:logger}\s+method=%{WORD:http_method}\s+path=%{DATA:http_path}\s+status=%{NUMBER:http_status:int}\s+duration_ms=%{NUMBER:duration_ms:int}\s*:\s%{GREEDYDATA:msg}$"&lt;/span&gt;
      &lt;span class="s"&gt;]&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;

  &lt;span class="s"&gt;date {&lt;/span&gt;
    &lt;span class="s"&gt;match    =&amp;gt; [ "timestamp", "yyyy-MM-dd HH:mm:ss.SSS" ]&lt;/span&gt;
    &lt;span class="s"&gt;target   =&amp;gt; "@timestamp"&lt;/span&gt;
    &lt;span class="s"&gt;timezone =&amp;gt; "Europe/Paris"&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;

  &lt;span class="s"&gt;mutate {&lt;/span&gt;
    &lt;span class="s"&gt;rename =&amp;gt; {&lt;/span&gt; 
        &lt;span class="s"&gt;"msg" =&amp;gt; "message"&lt;/span&gt; 
        &lt;span class="s"&gt;"level"   =&amp;gt; "[log][level]"&lt;/span&gt;
        &lt;span class="s"&gt;"pid"     =&amp;gt; "[process][pid]"&lt;/span&gt;
        &lt;span class="s"&gt;"thread"  =&amp;gt; "[process][thread][name]"&lt;/span&gt;
        &lt;span class="s"&gt;"logger"  =&amp;gt; "[log][logger]"&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;

&lt;span class="s"&gt;output {&lt;/span&gt;
   &lt;span class="s"&gt;elasticsearch {&lt;/span&gt; 
       &lt;span class="s"&gt;hosts =&amp;gt; ["http://elasticsearch:9200"]&lt;/span&gt;
       &lt;span class="s"&gt;user =&amp;gt; "elastic"&lt;/span&gt;
       &lt;span class="s"&gt;password =&amp;gt; "${ELASTIC_PASSWORD}"&lt;/span&gt;  
       &lt;span class="s"&gt;ssl_certificate_verification =&amp;gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
       &lt;span class="s"&gt;data_stream =&amp;gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
       &lt;span class="s"&gt;index =&amp;gt; "logstash-%{+YYYY.MM.dd}"&lt;/span&gt;
   &lt;span class="s"&gt;}&lt;/span&gt;
   &lt;span class="s"&gt;# For debugging&lt;/span&gt;
   &lt;span class="s"&gt;stdout {&lt;/span&gt; 
    &lt;span class="s"&gt;codec =&amp;gt; rubydebug&lt;/span&gt; 
   &lt;span class="s"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Settings file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Logstash setting file logstash.yml
http.host: "0.0.0.0"
path.config: /usr/share/logstash/pipeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3. Kibana
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Kibana configuration file&lt;/span&gt;
&lt;span class="c1"&gt;# kibana.yml&lt;/span&gt;
&lt;span class="na"&gt;server.name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kibana&lt;/span&gt;
&lt;span class="na"&gt;server.host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0"&lt;/span&gt;
&lt;span class="na"&gt;elasticsearch.hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://elasticsearch:9200"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. The docker-compose file
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, you'll need to declare the three services and to connect them to the same network. We will call that network "elk".&lt;br&gt;&lt;br&gt;
Here is the content of our &lt;code&gt;docker-compose.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/elasticsearch/elasticsearch:8.14.3&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elasticsearch&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;discovery.type=single-node&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ELASTIC_PASSWORD=${ELASTIC_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./elasticsearch/data:/usr/share/elasticsearch/data&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9200:9200"&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-s"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:9200/_cluster/health?wait_for_status=yellow&amp;amp;timeout=50s"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5&lt;/span&gt;      
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;elk&lt;/span&gt;

  &lt;span class="na"&gt;logstash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/logstash/logstash:8.14.3&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logstash&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ELASTIC_PASSWORD=${ELASTIC_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./logstash/pipeline/:/usr/share/logstash/pipeline/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;C:/apps/logs:/usr/share/logstash/logs&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5044:5044"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;elk&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;

  &lt;span class="na"&gt;kibana&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/kibana/kibana:8.14.3&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kibana&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ELASTIC_PASSWORD=${ELASTIC_PASSWORD}&lt;/span&gt;    
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5601:5601"&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;elk&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;elk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridge&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following line &lt;strong&gt;C:/apps/logs:/usr/share/logstash/logs&lt;/strong&gt;, bind our spring boot application logs path to a path inside the Logstash container. This step is CRITICAL to ensure the logs move from your application to Logstash, and Elasticsearch afterward.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pro-tip: We have created an environment variable &lt;code&gt;ELASTIC_PASSWORD&lt;/code&gt; in the host machine, and we are passing it to the three services under the &lt;code&gt;environment&lt;/code&gt; setting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5.1. Elasticsearch Service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The discovery type is set to "single-node" because we are in a testing environment and only have a single instance of Elasticsearch. We don't want the overhead of cluster formation and management.&lt;/li&gt;
&lt;li&gt;Instead of leaving Elasticsearch to generate a password at startup, we have created a password and saved it in an environment variable. This way, we have total control over the password itself.&lt;/li&gt;
&lt;li&gt;We use "Volume binding" to bind the configuration file that we created in the host machine to the one in the Docker image. We don't want to content of Elasticsearch indices to be lost if the service restarts. So we bind the data directory "/usr/share/elasticsearch/data" to a directory in our host machine "./elasticsearch/data".&lt;/li&gt;
&lt;li&gt;We have created a &lt;strong&gt;health check&lt;/strong&gt; for Elasticsearch to make sure it is ready before the other services start.&lt;/li&gt;
&lt;li&gt;Lastly, we use port mapping to make Elasticsearch available on port 9200 from outside the container, and we attach the container to the "elk" network.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2. Logstash Service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Logstash has &lt;a href="https://www.elastic.co/guide/en/logstash/current/config-setting-files.html" rel="noopener noreferrer"&gt;two types of configuration&lt;/a&gt;: pipeline and setting configurations. We also use "Volume binding" to bind these configuration files from our host machine to those in the container.&lt;/li&gt;
&lt;li&gt;Logstash will be available on port 5044 and is attached to the "elk" network.&lt;/li&gt;
&lt;li&gt;Elasticsearch has to be ready before Logstash can start. We use "depends_on" to configure that behavior.&lt;/li&gt;
&lt;li&gt;Our Java Application ships its logs to "C:/apps/logs/springboot-rest.log" in the host machine. We have bound that directory to "/usr/share/logstash/logs" in the container.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3. Kibana Service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We also use "Volume binding" to bind the Kibana configuration file &lt;code&gt;kibana.yml&lt;/code&gt; from our host machine to the one in the container.&lt;/li&gt;
&lt;li&gt;Kibana will be available on port 5601 and is attached to the "elk" network.&lt;/li&gt;
&lt;li&gt;Just like Logstash, Kibana depends on Elasticsearch to be able to start.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Pro-tip: When you configure Elasticsearch and Kibana using Docker-compose in this way, you don't need to enroll Kibana using an enrollment token as you would do if you had configured each of the services individually.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  6. Start the Services
&lt;/h2&gt;

&lt;p&gt;Once the configuration files are created and the &lt;strong&gt;docker-compose&lt;/strong&gt; file is ready, use the following command to start the services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker-compose up
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can access the container logs using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker-compose logs -f
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Verify the installation
&lt;/h2&gt;

&lt;p&gt;Look into each service's logs to ensure it started properly.&lt;br&gt;
&lt;strong&gt;Elasticsearch&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker-compose logs -f elasticsearch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Logstash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker-compose logs -f logstash
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kibana&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;docker-compose logs -f kibana
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The option "-f" is used to have the logs in real-time, similarly to "tail -f"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  8. Shipping Your Java Application Logs
&lt;/h2&gt;

&lt;p&gt;Now that your ELK stack is running, let's get your Java logs into it. You don't need to change your existing logging statements(like &lt;code&gt;logger.info()&lt;/code&gt;); you just need to ensure your application logs are written to a file.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.1. For our &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/spring-boot/spring-boot-rest" rel="noopener noreferrer"&gt;Spring Boot REST Application&lt;/a&gt; using Logback:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Create or edit your logback-spring.xml
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;property&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"LOG_FILE"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"C:/apps/logs/springboot-rest.log"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;property&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"LOG_PATTERN"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%thread] %logger{36} method=%X{method} path=%X{path} status=%X{status} duration_ms=%X{duration_ms} : %msg%n"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Appender to write to the console --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;appender&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Console"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.core.ConsoleAppender"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;encoder&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;pattern&amp;gt;&lt;/span&gt;${LOG_PATTERN}&lt;span class="nt"&gt;&amp;lt;/pattern&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/encoder&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/appender&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Appender to write to a file --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;appender&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"File"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.core.rolling.RollingFileAppender"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;file&amp;gt;&lt;/span&gt;${LOG_FILE}&lt;span class="nt"&gt;&amp;lt;/file&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;encoder&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;pattern&amp;gt;&lt;/span&gt;${LOG_PATTERN}&lt;span class="nt"&gt;&amp;lt;/pattern&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/encoder&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;rollingPolicy&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fileNamePattern&amp;gt;&lt;/span&gt;C:/apps/logs/springboot-rest.log.%d{yyyy-MM-dd}.%i.log.gz&lt;span class="nt"&gt;&amp;lt;/fileNamePattern&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;maxFileSize&amp;gt;&lt;/span&gt;10MB&lt;span class="nt"&gt;&amp;lt;/maxFileSize&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;maxHistory&amp;gt;&lt;/span&gt;30&lt;span class="nt"&gt;&amp;lt;/maxHistory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/rollingPolicy&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/appender&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Root logging level --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;root&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"info"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;appender-ref&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"Console"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;appender-ref&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"File"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this config, &lt;code&gt;C:/apps/logs/springboot-rest.log&lt;/code&gt; is the location of our Spring Boot application logs. Feel free to adjust it accordingly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Restart your Java application.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;mvn spring-boot:run
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your logs will now be shipped to Logstash and appear in Kibana!&lt;/p&gt;

&lt;h4&gt;
  
  
  View the Logs in Kibana
&lt;/h4&gt;

&lt;p&gt;Navigate to  &lt;a href="http://127.0.0.1:5601/" rel="noopener noreferrer"&gt;http://127.0.0.1:5601/&lt;/a&gt; and you should see the Kibana welcome page. Kibana will invite you to create a DataView to be able to visualize the content of Elasticsearch indices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jbxmja9gyheh6eslkb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9jbxmja9gyheh6eslkb7.png" alt="kibana-create-dataview-welcome.png" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, you need to create a Dataview to be able to visualize the content of Logstash indices. Follow this tutorial about &lt;a href="https://nkamphoa.com/debug-java-application-with-kibana/" rel="noopener noreferrer"&gt;debugging a Java application with Kibana&lt;/a&gt; to configure your Logstash dataview. Once everything is configured, you should see a screen similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpo8adwdz6usssvnol24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpo8adwdz6usssvnol24.png" alt="elk-spring-boot-logs.png" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it! You've set up a &lt;strong&gt;centralised logging infrastructure for your Java application&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Conclusion
&lt;/h2&gt;

&lt;p&gt;You've now successfully built a powerful logging infrastructure for your Java projects. This Docker Compose setup is ideal for development and staging environments. By configuring your Java app to ship its logs to ELK, you've closed the loop and can now debug and monitor your applications more effectively than ever.  You should be aware that the setup we did in this tutorial is only for a testing environment and is unsuitable for production. Kindly have a look at &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.14/docker.html#docker-prod-prerequisites" rel="noopener noreferrer"&gt;these recommendations&lt;/a&gt; if you plan to run the ELK Stack in production with Docker.  &lt;/p&gt;

&lt;p&gt;Originally published at: &lt;a href="https://nkamphoa.com/devops-centralize-java-app-logs-with-elk-stack/" rel="noopener noreferrer"&gt;https://nkamphoa.com/devops-centralize-java-app-logs-with-elk-stack/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>elasticsearch</category>
    </item>
    <item>
      <title>Exception Hierarchy in Java: Checked, Unchecked, and Errors</title>
      <dc:creator>Noel KAMPHOA</dc:creator>
      <pubDate>Fri, 15 Aug 2025 18:49:59 +0000</pubDate>
      <link>https://dev.to/noel_kamphoa_e688aece0725/exception-hierarchy-in-java-checked-unchecked-and-errors-1f45</link>
      <guid>https://dev.to/noel_kamphoa_e688aece0725/exception-hierarchy-in-java-checked-unchecked-and-errors-1f45</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Understanding the &lt;strong&gt;Exception Hierarchy&lt;/strong&gt; in Java is vital for writing reliable and maintainable code. &lt;a href="https://nkamphoa.com/exception-in-java" rel="noopener noreferrer"&gt;Exceptions&lt;/a&gt; in Java are represented through a structured class hierarchy, rooted in the &lt;code&gt;Throwable&lt;/code&gt; class. This hierarchy helps developers categorize and handle different error conditions efficiently, whether they are recoverable or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Root of the Hierarchy: Throwable
&lt;/h2&gt;

&lt;p&gt;At the top of the Exception Hierarchy is the &lt;code&gt;Throwable&lt;/code&gt; class. It has two direct subclasses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Error&lt;/code&gt;: Represents serious problems that applications should not try to catch.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Exception&lt;/code&gt;: Indicates conditions that a program might want to catch.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Throwable&lt;/span&gt;
 &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;
 &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;"To handle exceptions effectively, you must first understand where they come from."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Errors in Java
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Error&lt;/code&gt; class and its subclasses represent critical conditions, such as &lt;code&gt;OutOfMemoryError&lt;/code&gt; or &lt;code&gt;StackOverflowError&lt;/code&gt;, that are not meant to be caught by applications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Simulate error (not recommended in practice)&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StackOverflowError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Critical Error"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Caught an Error: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In most real-world scenarios, these are logged and allowed to propagate.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Checked Exceptions
&lt;/h2&gt;

&lt;p&gt;Checked exceptions are subclasses of &lt;code&gt;Exception&lt;/code&gt; (but not &lt;code&gt;RuntimeException&lt;/code&gt;). They must be either caught or declared using the &lt;code&gt;throws&lt;/code&gt; keyword.  &lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IOException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SQLException&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IOException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"File not found"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Handled checked exception: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checked exceptions encourage explicit error handling and are checked at compile-time.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Unchecked Exceptions
&lt;/h2&gt;

&lt;p&gt;Unchecked exceptions extend the &lt;code&gt;RuntimeException&lt;/code&gt; class.  &lt;/p&gt;

&lt;p&gt;These include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nkamphoa.com/how-to-fix-nullpointerexception-in-java/" rel="noopener noreferrer"&gt;NullPointerException&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nkamphoa.com/how-to-fix-arrayindexoutofboundsexception-in-java/" rel="noopener noreferrer"&gt;ArrayIndexOutOfBoundsException&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IllegalArgumentException&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are not required to be declared or caught, but should still be handled when possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Throws NullPointerException&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NullPointerException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Caught unchecked exception: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;"Unchecked exceptions don't require you to catch them, but professional code often does."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. Custom Exceptions
&lt;/h2&gt;

&lt;p&gt;Developers can define their own exception classes by extending &lt;code&gt;Exception&lt;/code&gt; or &lt;code&gt;RuntimeException&lt;/code&gt;. This enables application-specific error reporting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomException&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CustomException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Custom exceptions improve clarity and allow better abstraction for domain-specific problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Summary of Exception Hierarchy
&lt;/h2&gt;

&lt;p&gt;Here's a summarized view of the Exception Hierarchy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Throwable
 ├── Error
 │   └── OutOfMemoryError, StackOverflowError, etc.
 └── Exception
     ├── IOException, SQLException, etc. (Checked)
     └── RuntimeException
         ├── NullPointerException, IndexOutOfBoundsException, etc. (Unchecked)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding this structure is critical when designing exception handling strategies. For deeper insights into practical handling, see our article on &lt;a href="https://nkamphoa.com/exception-in-java/" rel="noopener noreferrer"&gt;Handling exceptions in Java&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Exception Hierarchy in Java provides a systematic way to represent and manage errors. Differentiating between errors, checked, and unchecked exceptions empowers developers to write robust and readable code. By mastering this hierarchy, developers can improve both the quality and clarity of their exception handling practices.&lt;/p&gt;

&lt;p&gt;You can find the complete code of this article &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/core-java-modules/learning-paths/javase-ocp/practitioner/exception-handling" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally published at: &lt;a href="https://nkamphoa.com/exception-hierarchy-in-java/" rel="noopener noreferrer"&gt;https://nkamphoa.com/exception-hierarchy-in-java/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Understand the Factory Method Pattern in Java</title>
      <dc:creator>Noel KAMPHOA</dc:creator>
      <pubDate>Sat, 21 Jun 2025 11:43:33 +0000</pubDate>
      <link>https://dev.to/noel_kamphoa_e688aece0725/understand-the-factory-method-pattern-in-java-26ka</link>
      <guid>https://dev.to/noel_kamphoa_e688aece0725/understand-the-factory-method-pattern-in-java-26ka</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;In object-oriented programming, the Factory Method Pattern is a widely used &lt;strong&gt;creational design pattern&lt;/strong&gt; that provides a robust solution for object instantiation. Instead of creating objects directly using constructors, this pattern suggests using factory methods to encapsulate the instantiation logic.&lt;/p&gt;

&lt;p&gt;According to the Gang of Four (GoF), &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Factory Method lets a class defer instantiation to subclasses." &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This design principle encourages loose coupling, flexibility, and adherence to the &lt;strong&gt;&lt;a href="https://nkamphoa.com/open-closed-principle-in-java/" rel="noopener noreferrer"&gt;Open/Closed Principle&lt;/a&gt;&lt;/strong&gt;—a cornerstone of clean code.&lt;/p&gt;

&lt;p&gt;In this article, we will explore how the Factory Method Pattern works in Java, its benefits, and practical use cases. If you’re new to design patterns, consider reading our introduction to the &lt;a href="https://nkamphoa.com/solid-principles-in-java/" rel="noopener noreferrer"&gt;SOLID principles&lt;/a&gt; for foundational context.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What Is the Factory Method Pattern?
&lt;/h2&gt;

&lt;p&gt;The Factory Method Pattern defines an interface for creating an object, but allows subclasses to alter the type of objects that will be created. Rather than calling a constructor directly, a method (often named &lt;code&gt;create&lt;/code&gt; or &lt;code&gt;getInstance&lt;/code&gt;) is used to encapsulate the logic of object creation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Characteristics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Delegates the instantiation logic to subclasses or factories&lt;/li&gt;
&lt;li&gt;Encourages adherence to programming to interfaces, not implementations&lt;/li&gt;
&lt;li&gt;Supports open-closed design by making it easy to introduce new product types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern is especially useful in frameworks, plugins, and systems where the exact class of the object to be created isn't known until runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Core Components
&lt;/h2&gt;

&lt;p&gt;The pattern typically consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Product&lt;/strong&gt;: An &lt;a href="https://nkamphoa.com/interfaces-in-java/" rel="noopener noreferrer"&gt;interface&lt;/a&gt; or &lt;a href="https://nkamphoa.com/abstract-classes-in-java/" rel="noopener noreferrer"&gt;abstract class&lt;/a&gt; that declares the common behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteProduct&lt;/strong&gt;: Specific implementations of the Product interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creator&lt;/strong&gt;: An &lt;a href="https://nkamphoa.com/abstract-classes-in-java/" rel="noopener noreferrer"&gt;abstract class&lt;/a&gt; or &lt;a href="https://nkamphoa.com/interfaces-in-java/" rel="noopener noreferrer"&gt;interface&lt;/a&gt; declaring the factory method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConcreteCreator&lt;/strong&gt;: Subclasses that implement the factory method to return instances of ConcreteProduct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these components helps reinforce key OOP principles like abstraction and &lt;a href="https://nkamphoa.com/inheritance-in-java-building-on-basics-for-powerful-programming/" rel="noopener noreferrer"&gt;inheritance&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Example Implementation
&lt;/h2&gt;

&lt;p&gt;Let’s consider a notification system that can send messages via Email or SMS. Instead of hard-coding object creation, we use a factory method to determine which notification service to instantiate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Product interface&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;notifyUser&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ConcreteProduct implementations&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailNotification&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;notifyUser&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sending an Email notification"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SMSNotification&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;notifyUser&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sending an SMS notification"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Creator with factory method&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotificationFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ConcreteCreators&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailFactory&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;NotificationFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;EmailNotification&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SMSFactory&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;NotificationFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SMSNotification&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Client Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;NotificationFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailFactory&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createNotification&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifyUser&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Sending an Email notification&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure makes it easy to add new notification types without modifying the existing codebase, aligning with good design practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Advantages of the Factory Method Pattern
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Loose Coupling&lt;/strong&gt;: Classes depend on abstractions, not concrete implementations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: New types can be added without changing existing code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Clarity&lt;/strong&gt;: Encapsulating creation logic simplifies client-side usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Testing&lt;/strong&gt;: Easier to mock and substitute implementations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As your codebase grows, these benefits become increasingly significant.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Use Cases in Real Projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Logging frameworks (e.g., log4j) use factory methods to create loggers.&lt;/li&gt;
&lt;li&gt;GUI toolkits create widgets depending on the platform.&lt;/li&gt;
&lt;li&gt;Connection factories in database access layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wherever object creation logic needs to vary, the Factory Method Pattern offers an elegant solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Conclusion
&lt;/h2&gt;

&lt;p&gt;The Factory Method Pattern in Java promotes clean code and flexible architecture by decoupling object creation from usage. It allows developers to design scalable and maintainable systems, especially in plugin-driven or layered applications. &lt;/p&gt;

&lt;p&gt;You can find the complete code of this article &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/core-java-modules/practitioner/inheritance-and-records" rel="noopener noreferrer"&gt;here on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally published on my blog at &lt;a href="https://nkamphoa.com/factory-method-pattern-in-java/" rel="noopener noreferrer"&gt;https://nkamphoa.com/factory-method-pattern-in-java/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>cleancode</category>
      <category>inheritance</category>
      <category>cleancoding</category>
    </item>
    <item>
      <title>Abstract Classes and Interfaces in Java</title>
      <dc:creator>Noel KAMPHOA</dc:creator>
      <pubDate>Tue, 27 May 2025 12:56:46 +0000</pubDate>
      <link>https://dev.to/noel_kamphoa_e688aece0725/abstract-classes-and-interfaces-in-java-3b55</link>
      <guid>https://dev.to/noel_kamphoa_e688aece0725/abstract-classes-and-interfaces-in-java-3b55</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In Java, both &lt;strong&gt;&lt;a href="https://nkamphoa.com/abstract-classes-in-java" rel="noopener noreferrer"&gt;abstract classes&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://nkamphoa.com/interfaces-in-java/" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;&lt;/strong&gt; allow you to define contracts and shared behavior for other classes. But when should you use one over the other?&lt;/p&gt;

&lt;p&gt;This article explores the differences, use cases, and practical examples of abstract classes and interfaces to help you choose the right approach for your design.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What is an Interface?
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;&lt;a href="https://nkamphoa.com/interfaces-in-java/" rel="noopener noreferrer"&gt;interface&lt;/a&gt;&lt;/strong&gt; defines a contract. It contains method signatures that implementing classes must provide.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A class implements an interface like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dog eats."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dog sleeps."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since Java 8, interfaces can also contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;default&lt;/code&gt; methods with implementation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;static&lt;/code&gt; methods&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;private&lt;/code&gt; methods (from Java 9+)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. What is an Abstract Class?
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;&lt;a href="https://nkamphoa.com/abstract-classes-in-java" rel="noopener noreferrer"&gt;abstract class&lt;/a&gt;&lt;/strong&gt; is a class that cannot be instantiated and may contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstract methods (no body)&lt;/li&gt;
&lt;li&gt;Concrete methods (with body)&lt;/li&gt;
&lt;li&gt;Fields and constructors
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;fuelUp&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Filling fuel"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A subclass must provide implementations for all abstract methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Vehicle&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Car is starting..."&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Key Differences
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Interface&lt;/th&gt;
&lt;th&gt;Abstract Class&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Inheritance type&lt;/td&gt;
&lt;td&gt;Implements&lt;/td&gt;
&lt;td&gt;Extends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple inheritance&lt;/td&gt;
&lt;td&gt;Yes (can implement many interfaces)&lt;/td&gt;
&lt;td&gt;No (can extend only one class)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Constructors&lt;/td&gt;
&lt;td&gt;Not allowed&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fields&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;public static final&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;Any access modifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method body allowed&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;default&lt;/code&gt;, &lt;code&gt;static&lt;/code&gt; (Java 8+)&lt;/td&gt;
&lt;td&gt;Yes (concrete + abstract methods)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use case&lt;/td&gt;
&lt;td&gt;Capability or contract&lt;/td&gt;
&lt;td&gt;Shared base behavior + state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4. When to Use What
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;&lt;a href="https://nkamphoa.com/interfaces-in-java/" rel="noopener noreferrer"&gt;interfaces&lt;/a&gt;&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to define a &lt;strong&gt;capability or contract&lt;/strong&gt; (e.g., &lt;code&gt;Comparable&lt;/code&gt;, &lt;code&gt;Runnable&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;You need to support &lt;strong&gt;multiple inheritance&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Use &lt;strong&gt;&lt;a href="https://nkamphoa.com/abstract-classes-in-java" rel="noopener noreferrer"&gt;abstract classes&lt;/a&gt;&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want to share &lt;strong&gt;common state or logic&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You want to provide a &lt;strong&gt;partially implemented blueprint&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Real-World Example: Notification System
&lt;/h2&gt;

&lt;p&gt;Let’s say you want to define a framework for sending notifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Notifier&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used when each implementation is completely independent (Email, SMS, Slack...).&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: Abstract class
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseNotifier&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LOG: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used when you want to enforce logging or setup logic in all notifiers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both abstract classes and interfaces are powerful tools in Java. Use them deliberately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nkamphoa.com/interfaces-in-java/" rel="noopener noreferrer"&gt;Interfaces&lt;/a&gt; = “what a class &lt;strong&gt;can do&lt;/strong&gt;”&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nkamphoa.com/abstract-classes-in-java" rel="noopener noreferrer"&gt;Abstract classes&lt;/a&gt; = “what a class &lt;strong&gt;is and shares&lt;/strong&gt;”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding the distinction makes your code more expressive, reusable, and aligned with object-oriented best practices.&lt;/p&gt;

&lt;p&gt;You can find the complete code of this article &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/core-java-modules/practitioner/interfaces-and-generics" rel="noopener noreferrer"&gt;here in GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally published on my blog at: &lt;a href="https://nkamphoa.com/abstract-classes-and-interfaces-in-java/" rel="noopener noreferrer"&gt;https://nkamphoa.com/abstract-classes-and-interfaces-in-java/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>oop</category>
      <category>cleancode</category>
      <category>cleancoding</category>
    </item>
    <item>
      <title>Single Responsibility Principle in Java</title>
      <dc:creator>Noel KAMPHOA</dc:creator>
      <pubDate>Sat, 17 May 2025 14:46:41 +0000</pubDate>
      <link>https://dev.to/noel_kamphoa_e688aece0725/single-responsibility-principle-in-java-4bko</link>
      <guid>https://dev.to/noel_kamphoa_e688aece0725/single-responsibility-principle-in-java-4bko</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Single Responsibility Principle (SRP)&lt;/strong&gt; is the “S” in the &lt;a href="https://nkamphoa.com/open-closed-principle-in-java" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; principles of &lt;a href="https://nkamphoa.com/object-oriented-in-java-building-robust-applications/" rel="noopener noreferrer"&gt;object-oriented design&lt;/a&gt;. It’s often mentioned, sometimes misunderstood, and rarely applied correctly in large Java applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: A class should have only one reason to change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In practice, this means a class should encapsulate &lt;strong&gt;a single, well-defined responsibility&lt;/strong&gt; — not “one method” or “one functionality,” but &lt;strong&gt;one axis of change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll go beyond trivial examples and explore &lt;strong&gt;real-world SRP violations&lt;/strong&gt;, how to spot them, and how to refactor for maintainability and testability.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. A Real-World Example: User Registration
&lt;/h2&gt;

&lt;p&gt;Consider the following &lt;code&gt;UserService&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BCrypt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashed&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// SMTP connection setup&lt;/span&gt;
        &lt;span class="c1"&gt;// Template rendering&lt;/span&gt;
        &lt;span class="c1"&gt;// Email dispatch&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks fine... until you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a new hashing algorithm&lt;/li&gt;
&lt;li&gt;Change email provider&lt;/li&gt;
&lt;li&gt;Handle registration for third-party OAuth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SRP is violated. Why?&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Identifying the Responsibilities
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;UserService&lt;/code&gt; class currently does &lt;strong&gt;at least three things&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Validates input&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manages user persistence&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handles email communication&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these concerns could change independently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marketing wants to change email templates.&lt;/li&gt;
&lt;li&gt;Security wants a new hashing policy.&lt;/li&gt;
&lt;li&gt;DevOps wants to decouple SMTP config.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All are &lt;em&gt;reasons to change&lt;/em&gt;. That’s your SRP alarm.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Refactoring for SRP
&lt;/h2&gt;

&lt;p&gt;Let’s extract each responsibility into its own class.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Extract validation:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistrationValidator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Extract password logic:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PasswordEncoder&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;BCrypt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✅ Extract email logic:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WelcomeMailer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;EmailClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;WelcomeMailer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EmailClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Welcome"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Thanks for joining!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔁 Updated &lt;code&gt;UserService&lt;/code&gt;:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;RegistrationValidator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;PasswordEncoder&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;WelcomeMailer&lt;/span&gt; &lt;span class="n"&gt;mailer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                       &lt;span class="nc"&gt;RegistrationValidator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                       &lt;span class="nc"&gt;PasswordEncoder&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                       &lt;span class="nc"&gt;WelcomeMailer&lt;/span&gt; &lt;span class="n"&gt;mailer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mailer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mailer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashed&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;mailer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each class has &lt;strong&gt;one reason to change&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;test independently&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Replacing email providers or validators becomes trivial&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. When Is SRP Worth It?
&lt;/h2&gt;

&lt;p&gt;Over-applying SRP can lead to fragmentation in &lt;strong&gt;small projects&lt;/strong&gt;. But in &lt;strong&gt;medium to large systems&lt;/strong&gt;, SRP is essential for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolated unit testing&lt;/li&gt;
&lt;li&gt;Team collaboration&lt;/li&gt;
&lt;li&gt;Clean domain boundaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good rule: &lt;strong&gt;When a class grows past 50–70 lines and touches multiple infrastructure layers, SRP may be at risk.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4.5. SRP vs. Microservices: A Note
&lt;/h2&gt;

&lt;p&gt;A common misunderstanding is to equate the &lt;strong&gt;Single Responsibility Principle (SRP)&lt;/strong&gt; with microservices — as if one microservice should only do one thing. But &lt;strong&gt;SRP applies at the class level&lt;/strong&gt;, not the system level.&lt;/p&gt;

&lt;p&gt;In fact, it’s possible (and common) to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have a &lt;strong&gt;monolith&lt;/strong&gt; that applies SRP cleanly within each service or module.&lt;/li&gt;
&lt;li&gt;Build a &lt;strong&gt;microservice&lt;/strong&gt; that violates SRP internally by mixing responsibilities into one giant class (e.g., a &lt;code&gt;UserService&lt;/code&gt; that also sends emails, logs metrics, and transforms DTOs).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SRP helps define &lt;strong&gt;cohesion within a module or microservice&lt;/strong&gt;, not how many services you should have.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Example
&lt;/h3&gt;

&lt;p&gt;Even in a microservice like &lt;code&gt;OrderService&lt;/code&gt;, you can still break SRP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createOrder&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendConfirmationEmail&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateInventory&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This service may be “small” and “independent,” but the class itself handles &lt;strong&gt;too many responsibilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The SRP-compliant version would delegate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OrderProcessor&lt;/code&gt; → handles core business logic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InventoryUpdater&lt;/code&gt; → manages stock&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NotificationService&lt;/code&gt; → sends emails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SRP helps you &lt;strong&gt;organize code within microservices&lt;/strong&gt;, not decide how many services to build.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Single Responsibility Principle helps you write Java code that is &lt;strong&gt;easier to change&lt;/strong&gt;, &lt;strong&gt;easier to test&lt;/strong&gt;, and &lt;strong&gt;easier to understand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the real world, SRP is less about counting methods and more about &lt;strong&gt;clarifying responsibilities&lt;/strong&gt;. When applied well, it becomes a foundation for clean, robust architecture.&lt;/p&gt;

&lt;p&gt;You can find the complete code of this article &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/core-java-modules/miscellaneous/misc-topics" rel="noopener noreferrer"&gt;here in GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📚 Related: &lt;a href="https://nkamphoa.com/open-closed-principle-in-java" rel="noopener noreferrer"&gt;Open/Closed Principle in Java&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Originally published on my blog: &lt;a href="https://nkamphoa.com/single-responsibility-principle-in-java/" rel="noopener noreferrer"&gt;https://nkamphoa.com/single-responsibility-principle-in-java/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cleancoding</category>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Mock Static Methods With Mockito</title>
      <dc:creator>Noel KAMPHOA</dc:creator>
      <pubDate>Wed, 14 May 2025 09:05:22 +0000</pubDate>
      <link>https://dev.to/noel_kamphoa_e688aece0725/how-to-mock-static-methods-with-mockito-554b</link>
      <guid>https://dev.to/noel_kamphoa_e688aece0725/how-to-mock-static-methods-with-mockito-554b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever gotten stuck writing automated tests for a class because it was using static method calls? Although &lt;strong&gt;the best practice is to refactor the code&lt;/strong&gt; so that it no longer uses static methods, in some cases this isn't possible. This is the case, for example, if the code in question does not belong to you. The &lt;code&gt;Path&lt;/code&gt; and &lt;code&gt;Files&lt;/code&gt; classes in the &lt;code&gt;java.nio&lt;/code&gt; package are practical examples. In this article, you will learn how to mock static methods using the Mockito library.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Application Under Test
&lt;/h2&gt;

&lt;p&gt;The application we are going to test has three main classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SalesProcessorStatic.java&lt;/code&gt;: This class has a unique method &lt;code&gt;compute&lt;/code&gt; that takes a list of strings representing the content of a CSV file. The String has the following structure &lt;code&gt;"productCode;saleAmount"&lt;/code&gt;. The &lt;code&gt;compute()&lt;/code&gt; method must return the total sales of the input List.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SaleLineParser&lt;/code&gt;: This class takes a string in the form &lt;code&gt;"productCode;saleAmount"&lt;/code&gt;, parses it, and returns a &lt;code&gt;Sale&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sale.java&lt;/code&gt;: is a simple Java record with two fields: &lt;code&gt;public record Sale(String productCode, int saleAmount) { }&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The SalesProcessorStatic.java class
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.kbytes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.function.Function&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SalesProcessorStatic&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SalesProcessorStatic&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nc"&gt;Sale&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;toSale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;SaleLineParserStatic:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toSale&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Sale:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;saleAmount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Class to be Mocked: SaleLineParserStatic.java
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.kbytes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SaleLineParserStatic&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="no"&gt;COLUMN_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Sale&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Sale&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;delimiter&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;saleData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delimiter&lt;/span&gt;&lt;span class="o"&gt;,-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isInvalidColumnCount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The file must have "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="no"&gt;COLUMN_COUNT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;" columns!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isInvalidField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The file data format is invalid!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Sale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isInvalidField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;isSaleInvalid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]);&lt;/span&gt;
            &lt;span class="n"&gt;isSaleInvalid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NumberFormatException&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
            &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;isSaleInvalid&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isInvalidColumnCount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;saleData&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saleData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;COLUMN_COUNT&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Sale.java Record
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Sale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;productCode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;saleAmount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from this line &lt;code&gt;Function&amp;lt;String,Sale&amp;gt; toSale = SaleLineParserStatic::parse&lt;/code&gt;, the &lt;code&gt;compute()&lt;/code&gt; method of the &lt;code&gt;SalesProcessorStatic&lt;/code&gt; class is making a static call to the &lt;code&gt;parse()&lt;/code&gt; method of &lt;code&gt;SaleLineParserStatic&lt;/code&gt;. To test the &lt;code&gt;SaleProcessorStatic&lt;/code&gt; class independently of the &lt;code&gt;SaleLineParserStatic&lt;/code&gt;, you have to mock the call to the static method &lt;code&gt;SaleLineParserStatic.parse()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Add the Maven Dependency
&lt;/h2&gt;

&lt;p&gt;The only dependencies that you will need are JUnit 5 Engine and Mockito Core.&lt;br&gt;&lt;br&gt;
Add the following dependencies to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.jupiter&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-jupiter-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.9.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mockito&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mockito-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.11.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Mock The Static Method with &lt;code&gt;MockedStatic&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Mocking static methods has been possible since &lt;a href="https://github.com/mockito/mockito/blob/release/3.x/doc/release-notes/official.md" rel="noopener noreferrer"&gt;Mockito 3.4.0&lt;/a&gt;.  The procedure for mocking a static method is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;mockStatic()&lt;/code&gt; method of the &lt;code&gt;Mockito&lt;/code&gt; class: &lt;code&gt;mockStatic(SaleLineParserStatic.class)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retrieve the object returned by the &lt;code&gt;mockStatic()&lt;/code&gt; method in a variable of type &lt;code&gt;MockedStatic&lt;/code&gt;: &lt;code&gt;MockedStatic&amp;lt;SaleLineParserStatic&amp;gt; mockSaleLineParser = mockStatic(SaleLineParserStatic.class)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configure the mock object: &lt;code&gt;mockSaleLineParser.when(() -&amp;gt; SaleLineParserStatic.parse("P1;10")).thenReturn(sale1)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the &lt;code&gt;MockedStatic&lt;/code&gt; class &lt;a href="https://github.com/mockito/mockito/blob/main/src/main/java/org/mockito/MockedStatic.java" rel="noopener noreferrer"&gt;Javadoc&lt;/a&gt;, you can read the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The static mock is released when this object's &lt;code&gt;MockedStatic#close()&lt;/code&gt; method is invoked. If this object is never closed, the static mock will remain active on the initiating thread. It is therefore recommended to create this object within a try-with-resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below is the complete test method for the &lt;code&gt;SalesProcessorStatic&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test_simple_compute&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;//given&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"P1;10"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"P2;20"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Sale&lt;/span&gt; &lt;span class="n"&gt;sale1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Sale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"P1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Sale&lt;/span&gt; &lt;span class="n"&gt;sale2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Sale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"P2"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;expectedTotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockedStatic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SaleLineParserStatic&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mockSaleLineParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mockStatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SaleLineParserStatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)){&lt;/span&gt;
        &lt;span class="n"&gt;mockSaleLineParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;SaleLineParserStatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"P1;10"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sale1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;mockSaleLineParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;SaleLineParserStatic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"P2;20"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sale2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;//when&lt;/span&gt;
        &lt;span class="nc"&gt;SalesProcessorStatic&lt;/span&gt; &lt;span class="n"&gt;salesProcessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SalesProcessorStatic&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;salesTotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;salesProcessor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;//then&lt;/span&gt;
        &lt;span class="nc"&gt;Assertions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedTotal&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;salesTotal&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that the mock object is closed at the end of the &lt;code&gt;try-with-resource&lt;/code&gt; block, the verifying part (Assertions) of your test must be within that same block.&lt;/p&gt;

&lt;p&gt;If you need to mock different classes in the same test, you should add them to the &lt;code&gt;try-with-resource&lt;/code&gt; block like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockedStatic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;FirstClassWithStaticMethod&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;firstMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mockStatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FirstClassWithStaticMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;MockedStatic&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SecondClassWithStaticMethod&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;secondMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mockStatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SecondClassWithStaticMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)){&lt;/span&gt;
        &lt;span class="c1"&gt;//your code  &lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this quick tutorial, you learned how to mock static methods using Mockito. If you want to learn how to use this approach to mock access to the FileSystem, check out &lt;a href="https://nkamphoa.com/how-to-mock-file-system-with-mockito/" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
The full code of this tutorial can be found &lt;a href="https://github.com/elkamphy/kloudly-tutorials/tree/master/core-java-modules/mock-static-method" rel="noopener noreferrer"&gt;here on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally published on my blog: &lt;a href="https://nkamphoa.com/how-to-mock-static-methods-with-mockito/" rel="noopener noreferrer"&gt;https://nkamphoa.com/how-to-mock-static-methods-with-mockito/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>testing</category>
      <category>tdd</category>
      <category>cleancode</category>
    </item>
  </channel>
</rss>
