How do I loop through the entries of a HashMap in Java?

You can use entrySet() with an enhanced for loop to read each key-value pair in a HashMap.

In this example, you will store product names and their quantities, then print each entry.

Source code

Save the following code as HashMapLoopExample.java:

import java.util.HashMap;
import java.util.Map;

public class HashMapLoopExample {
    void main() {
        Map<String, Integer> inventory = new HashMap<>();

        inventory.put("Notebook", 12);
        inventory.put("Pen", 30);
        inventory.put("Pencil", 20);

        for (Map.Entry<String, Integer> entry : inventory.entrySet()) {
            String product = entry.getKey();
            int quantity = entry.getValue();

            IO.println(product + ": " + quantity);
        }

        IO.println("Total products: " + inventory.size());
    }
}

Explanation

A map stores values associated with unique keys. In this example, each product name is a key, and its quantity is the corresponding value:

Map<String, Integer> inventory = new HashMap<>();

The type arguments specify that keys are strings and values are integers. Java generics use reference types, so the value type is Integer rather than int.

Adding entries

Use put() to add a key-value pair:

inventory.put("Notebook", 12);

Java automatically boxes the quantity into an Integer.

If you call put() again with an existing key, the new value replaces the previous value for that key.

Reading entries with entrySet()

The entrySet() method provides a set view of the map’s entries:

inventory.entrySet()

Each entry contains both a key and its associated value. The enhanced for loop reads one entry at a time:

for (Map.Entry<String, Integer> entry : inventory.entrySet()) {

Inside the loop, use getKey() and getValue() to access the pair:

String product = entry.getKey();
int quantity = entry.getValue();

Assigning the Integer value to an int automatically unboxes it. All values in this example are non-null.

Using entrySet() lets you read the key and value together without performing a separate lookup with get().

Counting entries

The size() method returns the number of key-value pairs:

inventory.size()

Here, the result is 3. It counts product entries, not the sum of their quantities.

Run the example

Compile and run the file:

javac HashMapLoopExample.java
java HashMapLoopExample

Example output

Notebook: 12
Pen: 30
Pencil: 20
Total products: 3

A HashMap does not guarantee iteration order, so the product lines may appear in a different order.

Using forEach()

For a shorter alternative, replace the loop with:

inventory.forEach((product, quantity) ->
        IO.println(product + ": " + quantity));

This passes each key and value to the lambda expression. It also follows the map’s iteration order, which remains unspecified for a HashMap.

How do I animate a falling domino spiral in Java Swing?

A domino chain reaction can be animated by giving each tile a slightly later start time. In this SwingLoops example, 92 dominoes are placed on a spiral. Each one appears to fall toward the next, changing from blue to orange as it moves. You can create the effect using Java Swing and Java 2D without a physics engine or external libraries.

Domino Spiral

Domino Spiral

Source code

Save this example as DominoSpiral.java.

package org.kodejava.swing.animation;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Path2D;

public class DominoSpiral extends JPanel {
    private static final int WIDTH = 450;
    private static final int HEIGHT = 800;
    private static final int COUNT = 92;
    private static final double START = 1.0;
    private static final double DELAY = 0.065;
    private static final double FALL = 0.24;
    private static final double CYCLE = 10.0;
    private static final Color BACKGROUND = new Color(10, 17, 31);

    private final double[] x = new double[COUNT];
    private final double[] y = new double[COUNT];
    private final double[] direction = new double[COUNT];
    private final Timer timer = new Timer(16, _ -> repaint());
    private long startedAt;

    public DominoSpiral() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(BACKGROUND);

        // Place the tiles about 13 pixels apart along the spiral.
        double angle = 0;
        double pitch = 8.5;
        for (int i = 0; i < COUNT; i++) {
            double radius = 195 - pitch * angle;
            x[i] = WIDTH / 2.0 + radius * Math.cos(angle);
            y[i] = HEIGHT / 2.0 + radius * Math.sin(angle);
            angle += 13 / Math.hypot(radius, pitch);
        }

        for (int i = 0; i < COUNT - 1; i++) {
            direction[i] = Math.atan2(y[i + 1] - y[i], x[i + 1] - x[i]);
        }
        direction[COUNT - 1] = direction[COUNT - 2];
    }

    @Override
    public void addNotify() {
        super.addNotify();
        startedAt = System.nanoTime();
        timer.start();
    }

    @Override
    public void removeNotify() {
        timer.stop();
        super.removeNotify();
    }

    private static double clamp(double value) {
        return Math.max(0, Math.min(1, value));
    }

    private static Color tileColor(double progress) {
        return new Color(
                57 + (int) (193 * progress),
                171 - (int) (54 * progress),
                248 - (int) (179 * progress));
    }

    private static void drawTile(Graphics2D g, double progress) {
        double lean = 10 * progress;
        double height = 20 - 14 * progress;

        g.setColor(new Color(2, 6, 13, 150));
        g.fillOval(-5, -6, 19, 12);

        Path2D face = new Path2D.Double();
        face.moveTo(0, -4);
        face.lineTo(0, 4);
        face.lineTo(lean + 5, 4 - height);
        face.lineTo(lean + 5, -4 - height);
        face.closePath();

        g.setColor(tileColor(progress));
        g.fill(face);
        g.setColor(new Color(255, 255, 255, 155));
        g.draw(face);
    }

    @Override
    protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);

        double elapsed = (System.nanoTime() - startedAt) / 1e9;
        double t = elapsed % CYCLE;
        double fade = t < 9 ? 1 : 1 - clamp(t - 9);
        Graphics2D g = (Graphics2D) graphics.create();
        try {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);

            double scale = Math.min(getWidth() / (double) WIDTH,
                    getHeight() / (double) HEIGHT);
            g.translate((getWidth() - WIDTH * scale) / 2,
                    (getHeight() - HEIGHT * scale) / 2);
            g.scale(scale, scale);
            g.setComposite(java.awt.AlphaComposite.SrcOver.derive((float) fade));

            g.setColor(new Color(31, 49, 72));
            Path2D track = new Path2D.Double();
            track.moveTo(x[0], y[0]);
            for (int i = 1; i < COUNT; i++) {
                track.lineTo(x[i], y[i]);
            }
            g.draw(track);

            for (int i = 0; i < COUNT; i++) {
                double u = clamp((t - START - i * DELAY) / FALL);
                double progress = u * u * (3 - 2 * u);
                Graphics2D tile = (Graphics2D) g.create();
                try {
                    tile.translate(x[i], y[i]);
                    tile.rotate(direction[i]);
                    drawTile(tile, progress);
                } finally {
                    tile.dispose();
                }
            }
        } finally {
            g.dispose();
        }
    }

    static void main() {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("SwingLoops - Domino Spiral");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(new DominoSpiral());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

Run the example

Open a terminal in the directory containing the file. With a JDK installed and a desktop environment available, run:

javac DominoSpiral.java
java DominoSpiral

The window opens with a preferred drawing area of 450 × 800 pixels. Resize it to fit your screen; the drawing keeps its proportions. Close the window to exit.

Place the tiles along a spiral

The code starts with a radius of 195 pixels and reduces it by 8.5 pixels for each radian of angular travel. Sine and cosine convert the radius and angle to a position on the screen.

Using the same angle increment everywhere would spread out the outer tiles and crowd the inner ones. Instead, the code uses this approximation:

angle += 13 / Math.hypot(radius, pitch);

For a small angle change, the distance traveled along this spiral is approximately the angle change multiplied by sqrt(radius² + pitch²). Dividing the desired spacing of 13 pixels by that factor gives an angle step that grows as the spiral tightens. The result is approximately even spacing. After placing the tiles, Math.atan2() determines which direction each tile should face by looking at the next tile.

Turn a delay into a chain reaction

The first tile starts one second into the cycle. Each later tile waits an additional 65 milliseconds:

double u = clamp((t - START - i * DELAY) / FALL);

A value of zero means the tile is upright, and one means it has finished falling. The fall takes 240 milliseconds, so several neighboring tiles are in motion at once. Smoothstep, u * u * (3 - 2 * u), eases the movement at both ends.

To draw the fall, the program shifts the tile’s upper edge forward and reduces its visible height. Its color shifts toward orange at the same time. This is a stylized 2D animation: the timing creates the apparent chain reaction, and the program does not calculate contact between tiles.

Repeat the animation

A Swing timer requests repaints about every 16 milliseconds. The drawing uses elapsed time from System.nanoTime(), so a delayed repaint does not change when the next tile is supposed to fall. During the final second the spiral fades away. At the ten-second boundary, the upright tiles reappear.

Try raising DELAY from 0.065 to 0.075 to slow down the chain. If you increase it further, check that START + (COUNT - 1) * DELAY + FALL still fits before the fade begins at nine seconds.

The complete source code is free to copy and run. Find more examples in the SwingLoops repository.

How do I remove duplicate values using a HashSet in Java?

A HashSet stores unique elements. You can use it to remove duplicate values from a collection by passing that collection to its constructor.

In this example, you will remove duplicate programming language names from a list.

Source code

Save the following code as RemoveDuplicatesExample.java:

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class RemoveDuplicatesExample {
    void main() {
        List<String> languages = List.of(
                "Java", "Python", "Java", "Kotlin", "Python");

        Set<String> uniqueLanguages = new HashSet<>(languages);

        IO.println("Original list: " + languages);
        IO.println("Original count: " + languages.size());
        IO.println("Unique count: " + uniqueLanguages.size());

        IO.println("Unique languages:");
        uniqueLanguages.stream()
                .sorted()
                .forEach(IO::println);
    }
}

Explanation

The original list contains five elements, including repeated values:

List<String> languages = List.of(
        "Java", "Python", "Java", "Kotlin", "Python");

Both "Java" and "Python" appear twice.

Creating a set from the list

The following statement copies the list’s elements into a HashSet:

Set<String> uniqueLanguages = new HashSet<>(languages);

A set does not retain duplicate elements, so the resulting set contains three language names.

The original list remains unchanged.

The variable uses the interface type Set<String>, while HashSet provides the implementation.

How duplicates are identified

HashSet uses hashCode() and equals() to identify duplicate elements.

For strings, equality depends on their text and is case-sensitive. For example, "Java" and "java" are different values and would both remain in the set.

When storing objects from your own classes, implement equals() and hashCode() consistently so the set can recognize logically equal objects.

Displaying the unique values

A HashSet does not guarantee iteration order. The example sorts the elements before printing them to produce predictable output:

uniqueLanguages.stream()
        .sorted()
        .forEach(IO::println);

stream() creates a stream of the set’s elements. sorted() arranges the strings in their natural order, and forEach() prints each one.

Sorting the stream does not change the set.

Run the example

Compile and run the file:

javac RemoveDuplicatesExample.java
java RemoveDuplicatesExample

Output

Original list: [Java, Python, Java, Kotlin, Python]
Original count: 5
Unique count: 3
Unique languages:
Java
Kotlin
Python

Preserving insertion order

If you want to remove duplicates while preserving the order in which values first appeared, use a LinkedHashSet:

Set<String> uniqueLanguages = new LinkedHashSet<>(languages);

Import java.util.LinkedHashSet to use it. Iterating over this set produces Java, Python, and Kotlin, in that order.

How Do I Build My First AI Application with Spring AI?

Building AI Applications with Spring AI, Part 1

In this example, you will build a Spring Boot API that answers questions about Java. Send a question to POST /api/ask, and Spring AI’s ChatClient will pass it to an OpenAI chat model. The endpoint returns the model’s answer as JSON.

Set up the project

Use JDK 25, Maven 3.9 or later, and an OpenAI API key with access to gpt-4o-mini. Copy the complete Maven POM at the end of this article into an empty project directory. The example uses Spring Boot 4.1.2 and Spring AI 2.0.2.

Create an OpenAI API key

  1. Sign in to the OpenAI Platform API Keys page.
  2. Select your project, then click Create new secret key. You can name it kodejava-spring-ai.
  3. Copy the secret key and store it securely. The platform displays the full key only when you create it.

API usage is billed separately from ChatGPT Plus. To enable paid API usage, add a payment method in API Billing.

Configure the chat model

Create src/main/resources/application.properties:

server.address=127.0.0.1
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.model=gpt-4o-mini

Spring Boot reads the API key from the environment. Keep it out of source control. The loopback address makes the endpoint accessible on your own machine.

Create the application

Save the following class in src/main/java/org/kodejava/springai/JavaAssistantApplication.java:

package org.kodejava.springai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JavaAssistantApplication {
    public static void main(String[] args) {
        SpringApplication.run(JavaAssistantApplication.class, args);
    }
}

Create the REST controller

Save the controller in src/main/java/org/kodejava/springai/JavaAssistantController.java:

package org.kodejava.springai;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

@RestController
public class JavaAssistantController {
    private final ChatClient chatClient;

    public JavaAssistantController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @PostMapping("/api/ask")
    public AskResponse ask(@RequestBody AskRequest request) {
        if (request.question() == null || request.question().isBlank()) {
            throw new ResponseStatusException(
                    HttpStatus.BAD_REQUEST, "Question must not be blank");
        }

        String answer = chatClient.prompt()
                .system("You are a Java tutor. Explain concepts in plain English.")
                .user(request.question())
                .call()
                .content();

        return new AskResponse(answer);
    }

    public record AskRequest(String question) {}

    public record AskResponse(String answer) {}
}

Spring AI supplies the ChatClient.Builder, and the controller uses it to create a client once. The system message describes how the model should answer. The user message contains the question. The call().content() chain gets the model’s text synchronously, and Spring MVC serializes the response record as JSON.

A missing or blank question field returns HTTP 400 before the controller calls the model. Each request is independent, so include the topic when asking a follow-up question.

Run the application

On macOS or Linux:

export OPENAI_API_KEY='your-api-key'
mvn spring-boot:run

Run Maven in the same terminal where you set the key. Then open a second terminal to send a request:

curl http://127.0.0.1:8080/api/ask \
  -H 'Content-Type: application/json' \
  -d '{"question":"What is the difference between List and Set in Java?"}'

A possible response:

{
  "answer": "A List is ordered and allows duplicate elements. A Set contains unique elements. Its iteration order depends on the implementation."
}

The exact wording can vary. Try sending {"question":" "} to check the HTTP 400 response.

In Part 2, you will use a prompt template to adapt the explanation to the reader’s skill level.

References

Maven artifacts

The Spring Boot parent manages the Web MVC starter and Maven plugin versions. The Spring AI BOM manages the OpenAI starter version.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.1.2</version>
        <relativePath/>
    </parent>

    <groupId>org.kodejava</groupId>
    <artifactId>spring-ai-java-assistant</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>25</java.version>
        <spring-ai.version>2.0.2</spring-ai.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

How do I add and remove items from an ArrayList in Java?

An ArrayList stores elements in order and can grow or shrink as you add or remove items.

In this example, you will create a list of programming languages, add elements, and remove them by value and by index.

Source code

Save the following code as ArrayListExample.java:

import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    void main() {
        ArrayList<String> languages = new ArrayList<>(
                List.of("Java", "Python"));

        IO.println("Initial list: " + languages);

        languages.add("JavaScript");
        IO.println("After adding JavaScript: " + languages);

        languages.add(1, "Kotlin");
        IO.println("After inserting Kotlin: " + languages);

        boolean removed = languages.remove("Python");
        IO.println("Python removed: " + removed);
        IO.println("After removing Python: " + languages);

        String removedLanguage = languages.remove(0);
        IO.println("Removed at index 0: " + removedLanguage);
        IO.println("Final list: " + languages);

        IO.println("Total languages: " + languages.size());
    }
}

Explanation

The following statement creates a mutable list containing two strings:

ArrayList<String> languages = new ArrayList<>(List.of("Java", "Python"));

List.of() creates an unmodifiable list. Passing it to the ArrayList constructor copies its elements into a new list that supports adding and removing items.

The type argument <String> restricts this list to strings. The diamond operator <> lets the compiler infer the constructor’s type argument.

Adding an item

Use add(element) to append an item to the end:

languages.add("JavaScript");

The list becomes:

[Java, Python, JavaScript]

To insert an item at a specific position, use add(index, element):

languages.add(1, "Kotlin");

Indexes start at zero. This inserts "Kotlin" at the second position and shifts the following elements to the right.

Removing an item by value

Use remove(Object) to remove the first matching item:

boolean removed = languages.remove("Python");

This method returns true if an item was removed, or false if no matching item was found.

If the list contains duplicates, only the first matching occurrence is removed.

Removing an item by index

Use remove(int) to remove an item at a specific position:

String removedLanguage = languages.remove(0);

This removes the first item and returns it. The remaining elements shift to the left.

The index must refer to an existing element. Otherwise, the method throws an IndexOutOfBoundsException.

Getting the number of items

Use size() to read the number of elements:

languages.size()

Unlike an array’s length field, an ArrayList uses a method with parentheses.

Run the example

Compile and run the file:

javac ArrayListExample.java
java ArrayListExample

Output

Initial list: [Java, Python]
After adding JavaScript: [Java, Python, JavaScript]
After inserting Kotlin: [Java, Kotlin, Python, JavaScript]
Python removed: true
After removing Python: [Java, Kotlin, JavaScript]
Removed at index 0: Java
Final list: [Kotlin, JavaScript]
Total languages: 2

Removing integers by value

For an ArrayList<Integer>, passing an int to remove() selects the index-based overload:

numbers.remove(1);

This removes the element at index 1. To remove the value 1, explicitly pass an Integer:

numbers.remove(Integer.valueOf(1));