Robert Johns | 06 Mar, 2024
Fact checked by Jim Markus

How To Create A Java Chat Application for Beginners

Want to know how to build a Java chat application? In this tutorial, I’ll walk you through this fun and practical Java project step-by-step. 

Whether you’re just starting your Java development journey or are keen to learn Java, a Java chat application is a fun project for beginners to learn real-world Java skills.

In this Java tutorial, you'll:

  • Design an engaging UI for a Java chat application using Java Swing.
  • Implement core functionalities with Java, such as connecting to a chat server, sending messages, and displaying incoming messages in real time.
  • Dynamically update the chat interface based on user interactions, ensuring a smooth and responsive experience.
  • Introduce advanced features like user name entry, message timestamps, and a graceful exit mechanism with departure messages.
  • Apply final touches and refinements to enhance the application's usability, appearance, and performance, preparing it for distribution and use.

To make the most of this tutorial, it helps to have basic Java skills, including familiarity with basic networking concepts and OOP.

Some previous experience with Java, such as working with Swing components for building user interfaces and handling events, can be beneficial. However, you don't need to be a Java expert or have prior experience with Java network programming or chat applications.

I’ve also provided the full source code for this Java project so you can follow along, experiment, and even build upon it for your own projects. 

Let’s dive in and start building!

How To Create A Java Chat Application

Are you ready to dive into the world of Java development and OOP with a hands-on Java project

If so, you're in the perfect place because today, we're going to create a chat application using Java. 

This project is an excellent starting point if you're new to Java or network programming, as it provides a clear and engaging example of how Java can be used to facilitate real-time communication over a network. 

At the core of our project, we'll be utilizing Java's networking capabilities to send and receive messages between clients and a server. 

Java, with its robust API for networking, makes it an ideal language for such applications, blending logic and interactivity to enable real-time data exchange.

In this simple chat application, Java will handle the backend logic, including client-server interactions, message broadcasting to multiple clients, and maintaining active connections. 

But we won't stop at functionality. We'll also dive into the basics of creating a user-friendly interface using Java Swing to make our chat application both powerful and pleasant to use.

Take a look at the image below to get an idea of what you’re going to build!

Build your own Java chat application

Now, you might wonder, "Is this going to be difficult to build?" Not at all! 

I've designed this Java project to be beginner-friendly, breaking it down into manageable, easy-to-follow steps. 

So, whether you're just starting your journey in Java development or you have some experience but are new to network programming, this project is a fantastic way to enhance your skills.

So, let's gear up, open our IDE, and get ready to create our very own chat application. 

By the end of this tutorial, you'll not only have a functional chat application to add to your portfolio but you'll also gain a deeper understanding of Java's networking capabilities and how to create interactive, real-time applications.

Let’s get started and build something exciting!

Project Prerequisites

Before we dive into the coding of our Java chat application, let's review the skills you'll need to follow along with me. 

And don't worry, you don't need to be a Java expert to get started, but having a few basics under your belt will make this journey smoother and more enjoyable. 

Plus, if you're rusty in any of these areas, you can always brush up with a Java course. Remember, we're also here to help, so don’t hesitate to search hackr.io for help as you go along.

Basic Java Knowledge

You should be comfortable with Java syntax and the fundamentals of object-oriented programming, including classes, objects, methods, and inheritance.

Understanding of Java Networking 

A basic understanding of networking concepts such as sockets and threads is beneficial, though we'll cover the essentials as we build our application.

Familiarity with Java Swing 

For creating the client interface, some basic knowledge of Swing will be helpful. However, this tutorial will provide the necessary guidance for beginners.

A Curious and Experimental Mind 

This might be the most crucial prerequisite! 

I really believe that when it comes to coding in Java, the most effective way to learn is through hands-on experience, making errors, and trying again. 

Be prepared to experiment, modify the code, and perhaps even cause a few glitches (which you'll then resolve). 

That's the essence of learning and development!

You could also consider using an AI coding assistant like GitHub Copilot to help out, but I’d recommend waiting until you’re 100% stuck, as this is where you really learn.

Step 1: Setting Up The Project

Alright! Let's kick things off by setting up our Java chat application project. 

This initial step is crucial as it lays the foundation for our entire application, ensuring we have a structured and organized workspace from the get-go.

i. Install Java Development Kit (JDK)

Before anything else, ensure that you have the Java Development Kit (JDK) installed on your computer. 

The JDK is essential for developing and running Java applications. If you haven't installed it yet, visit the Oracle website or search for a JDK version compatible with your system and follow the installation instructions.

ii. Choose and Set Up Your IDE

It’s time to choose an Integrated Development Environment for developing your Java chat application. 

If you’ve read my article on the best Java IDEs, you’ll see that I favor IntelliJ IDEA, Eclipse, and NetBeans.

But I’d also encourage you to check out VSCode if you’re already familiar with that coding environment and you’d like to carry on with what you know. 

Simply head to the VSCode extension marketplace and install the ‘Extension Pack for Java’ from Microsoft, and you’ll be good to go.

iii. Create a New Java Project

Once your IDE is ready, it's time to create a new Java project:

  1. Open your IDE and select the option to create a new project.
  2. Choose a Java project from the list of project types.
  3. Name your project something descriptive, like JavaChatApp.
  4. If prompted, set the JDK version to use for this project.
  5. Finish the setup process, and your IDE will generate the project structure for you.

iv. Organize Your Project Structure

Organize your project structure for better management and scalability. Here's a simple way to structure your Java chat application:

  • src: This directory will contain all your source code files.
  • com.yourname.javachatapp: Replace yourname with your or your organization's name. This will be your base package where your Java files will reside.
  • server: A package for your server-side code.
  • client: A package for your client-side code.
  • lib: If your project requires external libraries, you can place them in this directory.

v. Set Up a Version Control System (Optional but Recommended)

Consider initializing a Git repository in your project folder to manage your source code versions. 

Use the command line or your IDE's built-in Git support to create the repository. This step is highly recommended as it helps in tracking changes and collaborating with others.

vi. Verify Project Setup

To ensure everything is set up correctly, try running a simple "Hello World" Java program in your project environment. 

This test will confirm that your JDK and IDE are correctly configured:

public class HelloWorld {
  public static void main(String[] args) {
      System.out.println("Hello, Java Chat Application!");
  }
}

vii. Ready Your Development Environment

As we move forward with building the Java chat application, keep your IDE open and familiarize yourself with its layout and features. 

You'll be spending a lot of time here, writing code, debugging, and running your application.

And there you have it! You've successfully set up your Java Chat Application project. 

With the foundation laid down, we're ready to dive into the exciting parts of building our chat application. 

Let's proceed to Step 2, where we'll explore the basics of networking required for our chat application.

Step 2: Understanding Networking Basics

Now, let’s take a moment to dive into networking basics. 

This step is crucial because our chat application will rely on network communication to exchange messages between clients and a server. 

And when it comes to networking in Java, this is largely about using sockets and understanding the server-client architecture. 

These are fundamental to enabling communication between different processes over a network.

i. Brief Overview of Sockets

Sockets serve as the endpoints for bi-directional communication between two networked applications. They are associated with a specific port number, allowing the TCP protocol to determine the intended recipient application for the data.

Java's java.net.Socket class represents a socket, and it allows Java applications to communicate over the network in a platform-independent manner.

There are two types of sockets in Java:

  • ServerSocket: These are designed to listen for incoming network requests, execute an action based on the request, and potentially send a response back to the requester.
  • Socket: These are endpoints for communication between two machines.

ii. Introduction to Server-Client Architecture

In the server-client model, multiple clients connect to a server, and they communicate with the server to exchange information. 

The server runs continuously, listening for clients to make connection requests. The basic steps in setting up a server and client are:

Server:

  • Instantiate a ServerSocket, assigning it a specific port to monitor for incoming requests.
  • Use the ServerSocket's accept() method to await a client's connection, which halts execution until a connection is established.
  • After accepting a connection, the server can interact with the client using the Socket object that the accept() method provides.

Client:

  • Initialize a Socket object with the server's hostname and port number to establish a connection.
  • After the connection is successfully established, the client can use the Socket object to communicate with the server.

Next, let’s examine some code examples to illustrate these concepts in action.

Server:

import java.io.*;
import java.net.*;

public class ChatServer {
  public static void main(String[] args) throws IOException {
      ServerSocket serverSocket = new ServerSocket(2000); // Port number 2000
      System.out.println("Server started. Waiting for clients...");
      Socket clientSocket = serverSocket.accept();
      System.out.println("Client connected.");
      // Additional code to handle communication will be added later
  }
}

Client:

import java.io.*;
import java.net.*;

public class ChatClient {
  public static void main(String[] args) throws IOException {
      Socket socket = new Socket("localhost", 5000); // Connect to server on port 5000
      System.out.println("Connected to server.");
      // Additional code to handle communication will be added later
  }
}

In the next steps, we'll build on this foundational knowledge to actually implement the server and client parts of our chat application. 

We'll write code to send messages from the client to the server and then broadcast those messages to other clients, effectively creating a basic chat room. 

Step 3: Creating the Chat Server

Now, let’s get to work and start creating the chat server, which will act as the central hub for all client communications. 

This will accept connections from clients, receive messages from one client, and broadcast those messages to all other connected clients.

i. Create New Java File for the Server

In your project directory, create a new file named ChatServer.java

This should be located in the src folder if you're using an IDE like Eclipse or IntelliJ IDEA or directly in your project folder if you're using a simple text editor and compiling from the command line.

If you’re choosing to organize your code into packages, the first line in your ChatServer.java file should declare the package. 

For instance, if you named your package com.chatapp.server, the first line should be package com.chatapp.server;. 

If you're not using packages, you can skip this step!

ii. Setting Up the Server Socket

Now, we need to create a ServerSocket that listens for incoming client connections on a specified port. 

The choice of port number can be arbitrary, provided it's not already in use by another service on the server.

iii. Accepting Client Connections

Once the server is up, it needs to continuously listen for new client connections and accept them. 

This is typically done in a loop, where for each accepted connection, a new Socket is created to handle client communication.

iv. Spawning a New Thread for Each Client

To allow multiple clients to connect and communicate simultaneously, the server will spawn a new thread for each client connection. 

This thread will handle all communication with that client, allowing the server to remain responsive and accept additional connections.

v. Broadcasting Messages to Clients

The server needs to be able to receive messages from any client and broadcast these messages to all other connected clients. 

This requires keeping track of all connected clients and iterating over them to send out messages.

Now we’ve outlined what we need to do, here is the basic implementation of our chat server in Java:

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
  // List to keep track of all connected clients
  private static List<ClientHandler> clients = new ArrayList<>();

  public static void main(String[] args) throws IOException {
      ServerSocket serverSocket = new ServerSocket(5000);
      System.out.println("Server started. Waiting for clients...");

      while (true) {
          Socket clientSocket = serverSocket.accept();
          System.out.println("Client connected: " + clientSocket);

          // Spawn a new thread for each client
          ClientHandler clientThread = new ClientHandler(clientSocket, clients);
          clients.add(clientThread);
          new Thread(clientThread).start();
      }
  }
}

class ClientHandler implements Runnable {
  private Socket clientSocket;
  private List<ClientHandler> clients;
  private PrintWriter out;
  private BufferedReader in;

  public ClientHandler(Socket socket, List<ClientHandler> clients) throws IOException {
      this.clientSocket = socket;
      this.clients = clients;
      this.out = new PrintWriter(clientSocket.getOutputStream(), true);
      this.in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
  }

  public void run() {
      try {
          String inputLine;
          while ((inputLine = in.readLine()) != null) {
              // Broadcast message to all clients
              for (ClientHandler aClient : clients) {
                  aClient.out.println(inputLine);
              }
          }
      } catch (IOException e) {
          System.out.println("An error occurred: " + e.getMessage());
      } finally {
          try {
              in.close();
              out.close();
              clientSocket.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  }
}

In this code, we’ve done the following:

  • The ChatServer class starts a server that listens on port 5000. For each connecting client, it spawns a new thread represented by the ClientHandler class.
  • The ClientHandler class handles all communication with a connected client. It reads messages sent by the client and broadcasts them to all other clients.
  • We maintain a static list of all client handlers (clients) to keep track of connected clients and facilitate message broadcasting.

Now we have our code, let’s run it. We’ll start by compiling the Server.

If you’re using an IDE, your project should automatically compile when you build it. But make sure you have set up your project correctly to include the main class.

Alternatively, open a terminal or command prompt and navigate to the directory containing your ChatServer.java file. 

Compile the Java file into bytecode by running the following command:

javac ChatServer.java

This will generate a ChatServer.class file in the same directory, which is the compiled version of your server.

You can now start your server to check it’s working properly.

Again, if you’re using an IDE, there will be a play or run button that you can click to start your application. 

Ensure that ChatServer is selected as the main class before you run it.

Alternatively, you can use the command line. Just make sure you are in the same directory where your compiled .class files are located, and run the following command to start the server:

java ChatServer

But be sure to replace ChatServer with the full class name if your class is in a package, e.g., java com.chatapp.server.ChatServer.

Once the server is started, it should display a message indicating it is waiting for clients to connect, typically on the console or terminal output. 

This verifies that your server is running and listening on the specified port for incoming connections.

Congratulations on building this basic chat server! Great work!

You should now have your own chat server up and running, ready to accept client connections. 

Next, we'll turn our attention to the chat client, so let’s get started!

Step 4: Developing the Chat Client

Now we have our chat server up and running, it's time to create the client part of our application. 

The client will connect to the server, send messages, and receive broadcasts from other clients. Let's dive into the process.

i. Create a New Java File for the Client

In your project directory, create a new file named ChatClient.java

Just like I mentioned in step 3, this file should be located in the src folder if you're using an IDE like Eclipse or IntelliJ IDEA or directly in your project folder if you're using a simple text editor and compiling from the command line.

If your code is organized into packages, you’ll again need to add a package declaration at the top of your ChatClient.java file. 

For example, if your package is named com.chatapp.client, start the file with package com.chatapp.client;. 

If you're not using packages, you can skip this step!

ii. Setting Up the Client Socket

The client needs to establish a connection to the server using a Socket. This requires the server's IP address and the port number on which the server is listening.

iii. Sending Messages to the Server

The client should be able to send messages to the server. This involves setting up an output stream and writing messages to it.

iv. Receiving Messages from the Server

The client also needs to continuously listen for messages from the server. This can be done by setting up an input stream and reading from it in a loop.

v. Running the Client

The client application can be started after the server is running. It will connect to the server, and the user can start sending and receiving messages.

Now we’ve outlined what we need to do, here is the basic implementation of our chat client in Java:

import java.io.*;
import java.net.*;

public class ChatClient {
  private Socket socket = null;
  private BufferedReader inputConsole = null;
  private PrintWriter out = null;
  private BufferedReader in = null;

  public ChatClient(String address, int port) {
      try {
          socket = new Socket(address, port);
          System.out.println("Connected to the chat server");

          inputConsole = new BufferedReader(new InputStreamReader(System.in));
          out = new PrintWriter(socket.getOutputStream(), true);
          in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

          String line = "";
          while (!line.equals("exit")) {
              line = inputConsole.readLine();
              out.println(line);
              System.out.println(in.readLine());
          }

          socket.close();
          inputConsole.close();
          out.close();
      } catch (UnknownHostException u) {
          System.out.println("Host unknown: " + u.getMessage());
      } catch (IOException i) {
          System.out.println("Unexpected exception: " + i.getMessage());
      }
  }

  public static void main(String args[]) {
      ChatClient client = new ChatClient("127.0.0.1", 5000);
  }
}

In this code, we’ve done the following:

  • The ChatClient class establishes a connection to the chat server at the specified address and port.
  • It reads messages from the console and sends them to the server.
  • It also listens for messages from the server and prints them to the console.
  • The client runs in a loop until the user types "exit".

Now we have our code, let’s run it:

Compile the Client: Similar to the server, compile ChatClient.java using your IDE or at the command line with:

javac ChatClient.java

Start the Client: Run the compiled client using your IDE or with the command line as shown below. Make sure to run the server first so the client can connect to it!

java ChatClient

Congratulations! You've successfully created, compiled, and run your own Java chat server and client!

In the next steps, we’ll look at creating a GUI by using Java Swing. Keep up the excellent work!

Step 5: Designing the User Interface with Java Swing 

In this step, we will design a simple graphical user interface (GUI) for our chat client using Java Swing. 

For our chat app, we’ll focus on several Swing components, including frames, text areas, buttons, and text fields.

This will allow users to interact with our chat application through a windowed interface rather than the command line.

i. Create a New Java File for the GUI

In your project directory, where you have ChatServer.java and ChatClient.java, create a new file named ChatClientGUI.java.

This file will contain the code for your application's graphical user interface.

ii. Coding our GUI

To begin, we’ll have to import the necessary Swing and AWT components at the beginning of the ChatClientGUI.java file.

We’ll also be extending JFrame to provide a basic window for your application and using a JTextArea for displaying messages and a JTextField for typing new messages.

When it comes to handling user input, we’ll have an action listener for the textField and this will be looking for when the user presses Enter.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;

public class ChatClientGUI extends JFrame {
  private JTextArea messageArea;
  private JTextField textField;
  private ChatClient client;

  public ChatClientGUI() {
      super("Chat Application");
      setSize(400, 500);
      setDefaultCloseOperation(EXIT_ON_CLOSE);

      messageArea = new JTextArea();
      messageArea.setEditable(false);
      add(new JScrollPane(messageArea), BorderLayout.CENTER);

      textField = new JTextField();
      textField.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              client.sendMessage(textField.getText());
              textField.setText("");
          }
      });
      add(textField, BorderLayout.SOUTH);

      // Initialize and start the ChatClient
      try {
          this.client = new ChatClient("127.0.0.1", 5000, this::onMessageReceived);
          client.startClient();
      } catch (IOException e) {
          e.printStackTrace();
          JOptionPane.showMessageDialog(this, "Error connecting to the server", "Connection error",
                  JOptionPane.ERROR_MESSAGE);
          System.exit(1);
      }
  }

  private void onMessageReceived(String message) {
      SwingUtilities.invokeLater(() -> messageArea.append(message + "\n"));
  }

  public static void main(String[] args) {
      SwingUtilities.invokeLater(() -> {
          new ChatClientGUI().setVisible(true);
      });
  }
}

So, looking at our code, we can see that:

  • The GUI consists of a JTextArea for displaying messages and a JTextField for typing new messages.
  • When the user presses Enter after typing a message in the JTextField, the message is sent to the server via the ChatClient instance.
  • The constructor tries to initialize the ChatClient with the server's address and port and a method reference (this::onMessageReceived) to handle incoming messages.

Great stuff! But our work is not yet done! 

We need to make some modifications to our chat client so that it can be used by our new GUI.

Iii. Updating our Chat Client

Recall that the ChatClient.java file is the client-side networking component that handles the connection to the chat server, sending messages, and receiving messages.

Now, we need to make some adjustments:

  • Add a Constructor Parameter: Modify the constructor to accept a Consumer<String> parameter. This consumer will be called with incoming messages from the server.
  • Handle Incoming Messages: Inside the startClient method, read messages from the server in a loop. For each message received, call the consumer passed in the constructor.

Here is the modified code:

import java.io.*;
import java.net.*;
import java.util.function.Consumer;

public class ChatClient {
  private Socket socket;
  private BufferedReader in;
  private PrintWriter out;
  private Consumer<String> onMessageReceived;

  public ChatClient(String serverAddress, int serverPort, Consumer<String> onMessageReceived) throws IOException {
      this.socket = new Socket(serverAddress, serverPort);
      this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      this.out = new PrintWriter(socket.getOutputStream(), true);
      this.onMessageReceived = onMessageReceived;
  }

  public void sendMessage(String msg) {
      out.println(msg);
  }

  public void startClient() {
      new Thread(() -> {
          try {
              String line;
              while ((line = in.readLine()) != null) {
                  onMessageReceived.accept(line);
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }).start();
  }
}

Let’s summarize the effect of making these changes:

  • The ChatClientGUI class creates an instance of ChatClient in its constructor. It passes a lambda function that appends received messages to the messageArea.
  • The ChatClient class uses the passed consumer to handle incoming messages, effectively linking the networking code with the GUI.

Now we have our GUI code and our modified client code, let’s run it:

Compile the Client: Similar to our previous steps server, compile ChatClient.java and ChatClientGUI.java using your IDE or at the command line with:

javac ChatClient.java ChatClientGUI.java

Start the Client: Run the compiled client GUI using your IDE or with the command line as shown below. Again, make sure to run the server first so the client can connect to it!

java ChatClientGUI

Congratulations! You've successfully created, compiled, and run your own Java chat server with a fully functional GUI client!

Let’s keep up this momentum and move on to the next steps.

Step 6: Enhancing The Chat Application [Optional] 

Our app works great, but how about we take things a little further?

Let’s allow users to enter their names so we can see which messages are sent by which user. 

Plus, let’s add timestamps for each message that’s sent, along with an exit button so someone can leave the chat.

These are all standard features you’d expect to see in a chat application, so let’s stretch ourselves and get them added!

i. User Name Entry and Display

Firstly, we need to modify our ChatClientGUI to handle user names and timestamps.

// add new imports
import java.text.SimpleDateFormat;
import java.util.Date;

public ChatClientGUI() {
  // Existing initialization code...

  // Prompt for user name
  String name = JOptionPane.showInputDialog(this, "Enter your name:", "Name Entry", JOptionPane.PLAIN_MESSAGE);
  this.setTitle("Chat Application - " + name); // Set window title to include user name

  // Modify actionPerformed to include the user name and time stamp
  textField.addActionListener(e -> {
      String message = "[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + name + ": " + textField.getText();
      client.sendMessage(message);
      textField.setText("");
  });

  // Initialize and start the ChatClient with modifications for user name
  // Existing connection setup code...
}

Let’s summarize what’s happening in this modified code:

  • When the client starts, it prompts the user to enter their name through a dialog box. 
  • We use this name to update the application window's title and reflect the user's identity.
  • We’ve modified the action listener for the textField where users type their messages.
  • When the user presses Enter, we construct a message string that includes a formatted timestamp for the current date and time.
  • The new message string includes a timestamp and the user's name
  • This is sent to the server via the client.sendMessage method.
  • After sending a message, the text field is cleared and ready for the next message.

ii. Add Exit Button

To allow users to leave the chat gracefully, let’s also add an "Exit" button to the GUI that closes the connection and exits the application.

private JButton exitButton;

public ChatClientGUI() {
  // Existing GUI setup code...

  // Initialize the exit button
  exitButton = new JButton("Exit");
  exitButton.addActionListener(e -> System.exit(0)); // Exit the application
  JPanel bottomPanel = new JPanel(new BorderLayout());
  bottomPanel.add(textField, BorderLayout.CENTER);
  bottomPanel.add(exitButton, BorderLayout.EAST);
  add(bottomPanel, BorderLayout.SOUTH);

  // Existing client initialization code...
}

Let’s recap what’s happening in this code modification:

  • We’ve created a JButton named exitButton and given it the label "Exit". When it’s clicked, it will trigger the application to close.
  • We’ve added an action listener to the exitButton and this executes the System.exit(0) command when it’s clicked to show a status code of 0 (normal exit).
  • We’ve added a new JPanel named bottomPanel to hold both the text input field and the exitButton.

iii. Add User Exit Message

Things are shaping up nicely, but let’s add more features so that when a user exits, a message is sent to the server to let everyone else know that they’ve left the chat.

This is a standard feature in any real-world chat application, so it makes perfect sense to add this to our app.

Let’s do this by modifying the ChatClientGUI constructor where the exit button is initialized:

// Initialize the exit button with enhanced functionality
exitButton = new JButton("Exit");
exitButton.addActionListener(e -> {
  // Send a departure message to the server
  String departureMessage = name + " has left the chat.";
  client.sendMessage(departureMessage);
 
  // Delay to ensure the message is sent before exiting
  try {
      Thread.sleep(1000); // Wait for 1 second to ensure message is sent
  } catch (InterruptedException ie) {
      Thread.currentThread().interrupt();
  }
 
  // Exit the application
  System.exit(0);
});

Let’s summarize what we’ve done here:

  • We’ve modified the exitButton action listener to send an exit message to the server.
  • When the user clicks "Exit", the application constructs a departure message and this is sent to the server using the sendMessage method of the client instance.
  • After sending the departure message, we’ve made the application wait for 1 second to ensure the message is successfully sent to the server before terminating. 
  • The application then exits using System.exit(0) just as it did before.

Awesome stuff, our chat app is looking really professional, so great work on getting this far!

Let’s keep up the momentum and make our final changes by adding even more professional styling to our app’s UI.

Step 7: Enhancing The Chat App Styling [Optional]

By now, we have a fully functional chat application, but how about we spend a little more time working on the styling with Java Swing?

Of course, feel free to dive deep into this, but I’ll focus on improving the aesthetics of our chat application's GUI by applying modern colors, fonts, and other styling elements.

First, we’ll decide on a color scheme that's modern and easy on the eyes. We'll also select fonts that are readable and stylish.

Let’s also use a vibrant button color that stands out but is consistent with the overall color scheme, not to mention a high-contrast text color for readability:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ChatClientGUI extends JFrame {
  private JTextArea messageArea;
  private JTextField textField;
  private JButton exitButton; // Declare the exit button
  private ChatClient client;

  public ChatClientGUI() {
      super("Chat Application");
      setSize(400, 500);
      setDefaultCloseOperation(EXIT_ON_CLOSE);

      // Styling variables
      Color backgroundColor = new Color(240, 240, 240); // Light gray background
      Color buttonColor = new Color(75, 75, 75); // Darker gray for buttons
      Color textColor = new Color(50, 50, 50); // Almost black for text
      Font textFont = new Font("Arial", Font.PLAIN, 14);
      Font buttonFont = new Font("Arial", Font.BOLD, 12);

      // Apply styles to the message area
      messageArea = new JTextArea();
      messageArea.setEditable(false);
      messageArea.setBackground(backgroundColor);
      messageArea.setForeground(textColor);
      messageArea.setFont(textFont);
      JScrollPane scrollPane = new JScrollPane(messageArea);
      add(scrollPane, BorderLayout.CENTER);

      // Prompt for user name
      String name = JOptionPane.showInputDialog(this, "Enter your name:", "Name Entry", JOptionPane.PLAIN_MESSAGE);
      // Update the window title to include user's name
      this.setTitle("Chat Application - " + name);

      // Apply styles to the text field
      textField = new JTextField();
      textField.setFont(textFont);
      textField.setForeground(textColor);
      textField.setBackground(backgroundColor);
      textField.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              String message = "[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + name + ": "
                      + textField.getText();
              client.sendMessage(message);
              textField.setText("");
          }
      });

      // Apply styles to the exit button and initialize it
      exitButton = new JButton("Exit");
      exitButton.setFont(buttonFont);
      exitButton.setBackground(buttonColor);
      exitButton.setForeground(Color.WHITE);
      exitButton.addActionListener(e -> {
          // Send a departure message to the server
          String departureMessage = name + " has left the chat.";
          client.sendMessage(departureMessage);

          // Delay to ensure the message is sent before exiting
          try {
              Thread.sleep(1000); // Wait for 1 second to ensure message is sent
          } catch (InterruptedException ie) {
              Thread.currentThread().interrupt();
          }

          // Exit the application
          System.exit(0);
      });

      // Creating a bottom panel to hold the text field and exit button
      JPanel bottomPanel = new JPanel(new BorderLayout());
      bottomPanel.setBackground(backgroundColor); // Apply background color to the panel
      bottomPanel.add(textField, BorderLayout.CENTER);
      bottomPanel.add(exitButton, BorderLayout.EAST); // Add the exit button to the bottom panel
      add(bottomPanel, BorderLayout.SOUTH); // Add the bottom panel to the frame

      // Initialize and start the ChatClient
      try {
          this.client = new ChatClient("127.0.0.1", 5000, this::onMessageReceived);
          client.startClient();
      } catch (IOException e) {
          e.printStackTrace();
          JOptionPane.showMessageDialog(this, "Error connecting to the server", "Connection error",
                  JOptionPane.ERROR_MESSAGE);
          System.exit(1);
      }
  }

  private void onMessageReceived(String message) {
      // Use SwingUtilities.invokeLater to ensure thread safety when updating the GUI
      SwingUtilities.invokeLater(() -> messageArea.append(message + "\n"));
  }

  public static void main(String[] args) {
      // Ensure the GUI is created and updated on the Event Dispatch Thread
      SwingUtilities.invokeLater(() -> {
          new ChatClientGUI().setVisible(true);
      });
  }
}

So, what have we done here?

Let’s recap the styling modifications in the modified code:

  • Background and Text Colors: A cohesive color scheme with light gray for backgrounds and almost black for text enhances readability and modernizes the look.
  • Fonts: We’ve used Arial for both text and buttons, with a distinction in style (plain for text, bold for buttons), to improve readability and add a touch of sophistication.
  • Button Styling: The exit button is styled with a darker background and white text, making it visually appealing and easy to identify.

Although small, these enhancements transform our chat application into a more engaging and visually appealing platform, providing a better user experience.

Now, let’s push into the final stages of this tutorial by looking at testing.

Step 8: Testing the Application

Fantastic work on developing your Java chat application! 

Now, it's time to apply the finishing touches and rigorously test the application to ensure its functionality is flawless and the user experience is intuitive and engaging. 

For our chat application, testing could involve several key areas: functionality, usability, and interface design. 

Let’s take a look at how you could approach each of these:

i. Functionality Testing

  • Connection Test: Verify the client can successfully connect to the server. Test with multiple clients to ensure the server can handle simultaneous connections.
  • Message Sending and Receiving: Ensure messages typed by a user are correctly displayed in their chat window and broadcasted to other users. Test the visibility of the user's name and timestamp with the messages.
  • Exit Functionality: Check if the "Exit" button properly closes the client application. Confirm that a departure message ("[User] has left the chat.") is broadcasted to other users upon exit.
  • Error Handling: Simulate network failures to see how the application responds, e.g., the server goes down, loss of internet connection. Ensure appropriate error messages are displayed for different failure scenarios.

ii. Usability Testing

  • User Interface and Experience: Gather feedback on the app’s UI design, colors, fonts, and overall layout. Assess its intuitiveness: Is it clear how to send messages, exit the chat, etc.?
  • Performance: Test the application under different network conditions to evaluate its responsiveness. Check for any lag in message delivery or application slowdowns with multiple users.
  • Accessibility: Ensure the application is accessible, considering font sizes, color contrasts, and keyboard navigation.

iii. Interface Design Testing

  • Consistency: Verify the styling remains consistent across different OS and window sizes.
  • Responsiveness: Resize the application window to check for any UI elements behaving unexpectedly or becoming unusable.
  • Feedback Loop: Implement changes based on user feedback and retest to ensure improvements have been effective.

When it comes to conducting these tests, much of the functionality and usability testing will be manual due to the interactive nature of a chat application.

That said, you might want to consider using automated testing tools for stress-testing the server with many simultaneous connections.

I’d also highly encourage you to get a small group of real users to use the application and provide feedback on usability and any bugs they encounter.

And remember that testing should be an iterative process. After fixing issues, retest to ensure no new problems have been introduced and that the original issue has been resolved.

Now that you’ve reached this stage, other steps I’d encourage you to consider include

Documentation and Sharing:

  • Consider drafting a README file if you plan to showcase your project on platforms like GitHub, detailing the project setup and any noteworthy features.
  • Share your project within developer communities or on social media to engage with a broader audience and gather additional feedback.

Reflect and Plan Next Steps:

  • Reflect on the knowledge gained through this project and contemplate how these learnings can be applied to future endeavors.
  • Consider expanding your chat application with more complex features, like sound effects, user profiles, user avatars, user status messages, and more.

Great job on building and refining your Java chat application! Take a moment to appreciate your hard work!

Whether you're building this for fun, as a learning experience, or as a portfolio piece, you've developed valuable skills in programming, problem-solving, and user interface design.

Be proud of your work, share it with others, and consider what project you'll take on next!

Step 9: Final Touches and Packaging

After thorough testing and refinements, it's time to apply the final touches to your Java chat application and prepare it for distribution. 

This step is all about ensuring your application is polished, user-friendly, and ready for others to use.

i. Final Review and Refinement

  • Code Cleanup: Go through your code to remove any unused variables, methods, or imports. Ensure your code is well-commented and follows a consistent coding style for easy maintenance and readability.
  • UI Consistency Check: Review the GUI to ensure all elements align with the chosen design theme. Test the application on different screen sizes and resolutions to guarantee a consistent user experience.
  • Optimization: Optimize performance where possible, focusing on reducing latency and improving message delivery times. Ensure the application uses resources efficiently, minimizing its footprint on the user's system.
  • Security Review: Conduct a final security review to ensure there are no vulnerabilities, such as unprotected sensitive data or susceptibility to injection attacks.

ii. Documentation

  • User Guide: Create a user guide that includes installation instructions, features overview, and usage tips. Include troubleshooting steps for common issues users might encounter.
  • Developer Documentation: Document your code to help future developers understand and contribute to the project. Consider using tools like Javadoc to generate professional-looking documentation.

iii. Packaging and Distribution

  • Packaging the Application: For desktop apps, package your Java application as an executable JAR file. Use tools like Launch4j or JPackage to bundle your app into native installers for Windows, macOS, and Linux. Ensure all libraries are included in the package, and test the installation process on different OS.
  • Distribution Platforms: Choose appropriate platforms to distribute your application, such as GitHub for open-source projects or personal websites for broader distribution.
  • Web Application: Consider using Java Web Start (for older versions of Java) or creating applets if your application needs to run within a web browser, though modern security restrictions make desktop distribution more viable for most cases.

Next Steps & Further Learning

Congratulations on successfully building your own Java chat application!

This is a significant achievement, but your learning journey doesn't stop here. There are many ways to further your skills in Java development. Let's explore some ideas:

Learn More About Java

  • Java Enhancements: Explore more advanced Java concepts and apply them to your app. Could advanced features like user profiles or sound effects be added? How about letting users add a status message or even customize the UI?
  • Explore Frameworks: Experiment with Java frameworks to see how they can be used to build more dynamic and complex Java applications.

Join Online Communities and Collaborate

  • Engage in Forums: Participate in Java development forums and communities. Share your chat app, get feedback, and learn from others.
  • Contribute to Open Source: Consider making your chat app open-source and collaborate with others to improve it.

Keep Up with Trends and Best Practices

Stay updated with the latest trends in Java development. Subscribe to blogs like hackr.io, watch webinars, and join online courses.

Document and Share Your Learning Journey

  • Blog About Your Project: Write about your development process, challenges you faced, and how you overcame them. Share your blog with the developer community.
  • Share Your Code: Publish your code on platforms like GitHub. This not only showcases your work but also allows others to learn from your project.

Challenge Yourself Regularly

Take part in coding challenges or hackathons to sharpen your skills and learn new techniques.

And if you're hungry for more Java projects, check back regularly, as we’re constantly adding new step-by-step tutorials.

For example, have you taken a look at my tutorial on how to build a Java chess game?

Java Chat Application Full Source Code

Chat Server:

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
  private static List<ClientHandler> clients = new ArrayList<>();

  public static void main(String[] args) throws IOException {
      ServerSocket serverSocket = new ServerSocket(5000);
      System.out.println("Server started. Waiting for clients...");

      while (true) {
          Socket clientSocket = serverSocket.accept();
          System.out.println("Client connected: " + clientSocket);

          ClientHandler clientThread = new ClientHandler(clientSocket, clients);
          clients.add(clientThread);
          new Thread(clientThread).start();
      }
  }
}

class ClientHandler implements Runnable {
  private Socket clientSocket;
  private List<ClientHandler> clients;
  private PrintWriter out;
  private BufferedReader in;

  public ClientHandler(Socket socket, List<ClientHandler> clients) throws IOException {
      this.clientSocket = socket;
      this.clients = clients;
      this.out = new PrintWriter(clientSocket.getOutputStream(), true);
      this.in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
  }

  public void run() {
      try {
          String inputLine;
          while ((inputLine = in.readLine()) != null) {
              for (ClientHandler aClient : clients) {
                  aClient.out.println(inputLine);
              }
          }
      } catch (IOException e) {
          System.out.println("An error occurred: " + e.getMessage());
      } finally {
          try {
              in.close();
              out.close();
              clientSocket.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  }
}

Chat Client:

import java.io.*;
import java.net.*;
import java.util.function.Consumer;

public class ChatClient {
  private Socket socket;
  private BufferedReader in;
  private PrintWriter out;
  private Consumer<String> onMessageReceived;

  public ChatClient(String serverAddress, int serverPort, Consumer<String> onMessageReceived) throws IOException {
      this.socket = new Socket(serverAddress, serverPort);
      this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      this.out = new PrintWriter(socket.getOutputStream(), true);
      this.onMessageReceived = onMessageReceived;
  }

  public void sendMessage(String msg) {
      out.println(msg);
  }

  public void startClient() {
      new Thread(() -> {
          try {
              String line;
              while ((line = in.readLine()) != null) {
                  onMessageReceived.accept(line);
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }).start();
  }
}

Chat Client GUI:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ChatClientGUI extends JFrame {
  private JTextArea messageArea;
  private JTextField textField;
  private JButton exitButton;
  private ChatClient client;

  public ChatClientGUI() {
      super("Chat Application");
      setSize(400, 500);
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      Color backgroundColor = new Color(240, 240, 240);
      Color buttonColor = new Color(75, 75, 75);
      Color textColor = new Color(50, 50, 50);
      Font textFont = new Font("Arial", Font.PLAIN, 14);
      Font buttonFont = new Font("Arial", Font.BOLD, 12);

      messageArea = new JTextArea();
      messageArea.setEditable(false);
      messageArea.setBackground(backgroundColor);
      messageArea.setForeground(textColor);
      messageArea.setFont(textFont);
      JScrollPane scrollPane = new JScrollPane(messageArea);
      add(scrollPane, BorderLayout.CENTER);

      String name = JOptionPane.showInputDialog(this, "Enter your name:", "Name Entry", JOptionPane.PLAIN_MESSAGE);
      this.setTitle("Chat Application - " + name);
      textField = new JTextField();
      textField.setFont(textFont);
      textField.setForeground(textColor);
      textField.setBackground(backgroundColor);
      textField.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              String message = "[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] " + name + ": "
                      + textField.getText();
              client.sendMessage(message);
              textField.setText("");
          }
      });
      exitButton = new JButton("Exit");
      exitButton.setFont(buttonFont);
      exitButton.setBackground(buttonColor);
      exitButton.setForeground(Color.WHITE);
      exitButton.addActionListener(e -> {
          String departureMessage = name + " has left the chat.";
          client.sendMessage(departureMessage);
          try {
              Thread.sleep(1000);
          } catch (InterruptedException ie) {
              Thread.currentThread().interrupt();
          }
          System.exit(0);
      });

      JPanel bottomPanel = new JPanel(new BorderLayout());
      bottomPanel.setBackground(backgroundColor);
      bottomPanel.add(textField, BorderLayout.CENTER);
      bottomPanel.add(exitButton, BorderLayout.EAST);
      add(bottomPanel, BorderLayout.SOUTH);
      try {
          this.client = new ChatClient("127.0.0.1", 5000, this::onMessageReceived);
          client.startClient();
      } catch (IOException e) {
          e.printStackTrace();
          JOptionPane.showMessageDialog(this, "Error connecting to the server", "Connection error",
                  JOptionPane.ERROR_MESSAGE);
          System.exit(1);
      }
  }

  private void onMessageReceived(String message) {
      SwingUtilities.invokeLater(() -> messageArea.append(message + "\n"));
  }

  public static void main(String[] args) {
      SwingUtilities.invokeLater(() -> {
          new ChatClientGUI().setVisible(true);
      });
  }
}

Wrapping Up

Building a Java chat application is a great way to enhance your Java development skills and delve into creating interactive Java applications.

By developing this engaging and interactive Java chat application, you've tackled various challenges, including crafting a user-friendly interface, managing network communication, and dynamically updating the chat interface based on user interactions. 

In this tutorial, you’ve learned how to:

  • Use Java Swing to design a clean and attractive chat application GUI.
  • Write Java code to handle connecting to a chat server, sending messages, and receiving messages in real time.
  • Dynamically update the Swing components to reflect incoming messages and user actions, enhancing the interactive experience.
  • Respond to user inputs by adding event listeners for message sending and handling the exit process.
  • Implement additional features such as user name registration, message timestamps, and departure notifications to enrich the chat functionality.

You now possess the essential tools and knowledge needed to further develop and expand this Java chat application. 

You can introduce more sophisticated features, such as private messaging, user authentication, chat rooms, or even integrate the chat service into larger applications or services.

Your journey into the world of Java doesn't end here. With these new skills, you're well-equipped to experiment with more complex Java projects, explore other aspects of Java, and continue building fun and interactive apps.

Have fun and happy coding!

Want to sharpen up your Java development skills in 2024? Check out:

Udemy's Top Rated Course: Java 17 Masterclass: Start Coding in 2024

 

By Robert Johns

Technical Editor for Hackr.io | 15+ Years in Python, Java, SQL, C++, C#, JavaScript, Ruby, PHP, .NET, MATLAB, HTML & CSS, and more... 10+ Years in Networking, Cloud, APIs, Linux | 5+ Years in Data Science | 2x PhDs in Structural & Blast Engineering

View all post by the author

Subscribe to our Newsletter for Articles, News, & Jobs.

I accept the Terms and Conditions.
Thanks for subscribing! Look out for our welcome email to verify your email and get our free newsletters.

Disclosure: Hackr.io is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission.

In this article

Learn More

Please login to leave comments