How to create double linked list in Java

In Double Linked List we have each node pointing to the previous and next node. Here we will see how to create a custom Double Linked List in java.
Some properties of linked list is that, it has a node that can contain some value and then each node is linked to next node and also previous node. That's why we can traverse the linked list sequentially given we know the starting (head) node or last (tail) node.
Custom Linked List
class MyLinkedList<E> {

	/* first points to head of the list */
	public Node<E> first = null;

	/* last points to tail of the list */
	public Node<E> last = null;

	/**
	 * Add item to tail (end) of the List
	 * 
	 * @param item
	 * @return
	 */
	public boolean add(E item) {
		Node<E> newNode = new Node<E>(last, item, null);

		if (last == null) {
			// last points to the new node created
			first = newNode;
		} else {
			last.next = newNode;
		}
		// update last so that it points to the new node
		last = newNode;
		return true;
	}

	static class Node<E> {
		public E value;
		public Node<E> next;
		public Node<E> prev;

		Node(Node<E> prev, E element, Node<E> next) {
			this.value = element;
			this.next = next;
			this.prev = prev;
		}
	}

}
In the above implementation we have defined the main class MyLinkedList and inside it we defined a generic static class Node. Each Node object can hold a value and has links to previous (prev) and next nodes.
Create Instance of MyLinkedList
//create instance
MyLinkedList<Integer> list = new MyLinkedList<Integer>();

//add values 1,2,3,4,5
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Print the content of the node
//Get the first node (head node) and then print it by traversing all nodes
MyLinkedList.Node<Integer> node = list.first;
while (node != null) {
	System.out.println("Content of Node: " + node.value);
	node = node.next;
}
Terminal
Output
Content of Node: 1
Content of Node: 2
Content of Node: 3
Content of Node: 4
Content of Node: 5

About sealed classes and interfaces

Starting Java 17 we can now allow additional class modifiers like sealed, non-sealed etc. A sealed class or interface can be extended or implemented only by those classes and interfaces permitted to do so. Following are the keywords related to sealed classes.
New Keywords
    Earlier we had only two options, allow subclasses to inherit the parent class or interface or not at all. In the later case using Final class modifier. Using sealed we can take a more controlled middle path where the Parent Class or Interface can dictate the Sub classes which can inherit from the Class.

    Defining sealed class (Two Styles)

    Style One: Using permit keyword

    using the class modifiers sealed and permits we can create sealed classes. In the example bellow we are Defining abstract sealed class Tesla which permits three known subclasses Model3, ModelS and TeslaSUV.
    Tesla
    package java17.sealed;
    
    public abstract sealed class Tesla permits Model3, ModelS, TeslaSUV{
    	public abstract Integer maxRange();
    	public String basePrice() {
    		return "25000 USD";
    	}
    }
    
    //Subclass 1
    public final class Model3 extends Tesla {
    	@Override
    	public Integer maxRange() {
    		return 200;
    	}
    }
    
    //Subclass 2
    public final class ModelS extends Tesla {
    	@Override
    	public Integer maxRange() {
    		return 400;
    	}
    }
    
    //Subclass3 (non-sealed)
    public non-sealed class TeslaSUV extends Tesla {
    	@Override
    	public Integer maxRange() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    }
    
    

    Style Two: Using member classes

    In the following example we are creating a sealed class BMWCars and three member classes.
    BMWCars
    package java17.sealed;
    
    public sealed class BMWCars {
    
    	public final class BMW3 extends BMWCars implements ElectricVehicle{
    
    	}
    	
    	public final class BMWI extends BMWCars implements Vehicle {
    
    	}
    	
    	public non-sealed class BMWJV extends BMWCars implements Vehicle {
    
    	}
    
    }
    

    Rules for Defining Sealed Classes or Interfaces

    Both Class and Interface can be marked with sealed. Inherited child classes can be marked with either final, sealed and non-sealed. Every permitted subclass must directly extend the sealed class. A permitted subclass may be non-sealed so that it is open for extension by unknown subclasses.

    Summary

    With introduction of sealed classes we can define the known subclasses of an abstract class. In other words now we can enforce extension of classes that is known in compile time. It allows us to have greater control of class proliferation and improve security.

    Generating Random Number in Java

    This article summarizes different ways to use the Random() class in java to generate bounded or unbounded random numbers. It also shows another important feature of the class that is using seed to generate same set of random numbers.
    java.util.Random used used to generate bounded or unbounded random numbers. It supports specifying a seed which is used to set the internal state of the pseudorandom number generator. Random(): creates new random generator Random(long seed): creates new random generator using specified seed
    Unbounded generate 5 random numbers
    Following code prints 5 random numbers unbounded without any seed
    public static void generateRadom() {
    	System.out.println("\nPrinting 10 Random Numbers");
    	Random generator = new Random();
    	for (int i = 0; i < 5; i++) {
    		System.out.print(generator.nextInt() + " ");
    	}
    }
    Invocation 1
    Printing 5 Random Numbers -1937915077 75383412 -901884443 1725835531 1371480362
    Invocation 2
    Printing 5 Random Numbers -1261854044 328673857 -1787159304 446964878 -283294822
    Notice that in both the invocations the generated numbers are different. This is because we have not set any seed in the Random Class.
    Random Bounded Number
    Following method will generate 5 random numbers between 0 and 99
    public static void generateRadomBounded() {
    	System.out.println("\nPrinting 5 Random Numbers Between 0 and 99");
    	Random generator = new Random();
    	for (int i = 0; i < 5; i++) {
    		System.out.print(generator.nextInt(100) + " ");
    	}
    }
    Invocation 1
    Printing 5 Random Numbers Between 0 and 99 25 95 13 60 67
    Invocation 2
    Printing 5 Random Numbers Between 0 and 99 17 10 21 96 15
    Generate Random number bounded with a seed
    Bellow function will generate bounded 5 random numbers but since we are setting a seed, if the seed is same on multiple invocation then each invocation will generate the same set of random numbers.
    public static void generateRadomWithSeed(long seed) {
    	System.out.println("\nPrinting 5 Random Numbers Between 0 and 99 with seed");
    	Random generator = new Random(seed);
    	for (int i = 0; i < 5; i++) {
    		System.out.print(generator.nextInt(100) + " ");
    	}
    }
    Invocation 1
    Printing 5 Random Numbers Between 0 and 99 with seed 4 62 52 3 58 67
    Invocation 2
    Printing 5 Random Numbers Between 0 and 99 with seed 4 62 52 3 58 67
    Summary
    • If we want to generate the same set of random numbers, we can set seed.
    • Test cases can use seed to make sure it gets same set of random numbers.
    • We can have bounded or unbounded random numbers.

    Java Threads Print Alternative Odd Even Numbers

    This article shows how to print Even and Odd numbers alternatively using Java. It uses Two Java threads and a Class with two methods to print even numbers and odd numbers respectively.

    What we are trying to achieve

    We want to print even and odd numbers alternatively but using two threads. Essentially it is the interaction between two threads utilizing the wait() and notify() methods. One thread completes a task (printing a single even number) then it is put on wait state so that the other thread can get a chance to do its job (printing odd number) and this goes on until we are done with printing a set of numbers determined by max.
    How it will work
    • Print Class (Print.java) with two synchronized methods even() and odd() which print even or odd numbers respectively.
    • Each method is synchronized so that two threads cannot execute them concurrently.
    • Each method first calls notifyAll() to so that other threads that are waiting can be wake up.
    • It then prints a number (even or odd) and then calls the wait() method on the current thread so it goes to waiting state.

    Java Code

    Print.java
    This Class essentially has two synchronized methods. The constructor of this class takes a max number as a parameter. This max number is the limit to which the numbers will be printed. It has two synchronized methods to print even and odd numbers alternatively.
    class Print {
      int max;
    
      public Print(int max) {
        this.max = max;
      }
    
      public synchronized void even() throws InterruptedException {
        for (int i = 0; i <= max; i++) {
          notifyAll();
          if (i % 2 == 0)
            System.out.println(Thread.currentThread().getName() + ":: " + i);
          wait();
        }
      }
    
      public synchronized void odd() throws InterruptedException {
        for (int i = 0; i <= max; i++) {
          notifyAll();
          if (i % 2 != 0)
            System.out.println(Thread.currentThread().getName() + ":: " + i);
          wait();
        }
      }
    }
    Threads.java
    Here we are creating an instance of Print class and creating two Threads. From the first thread, we are calling print.even() method, from the second thread we are calling print.odd() method.
    Print print = new Print(10);
    
    //Thread to print even numbers
    Thread t1 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          print.even();
        } catch (InterruptedException e) {
        }
      }
    });
    
    //Thread to print odd numbers
    Thread t2 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          print.odd();
        } catch (InterruptedException e) {
        }
      }
    });
    
    t1.setName("Even Thread");
    t2.setName(" Odd Thread");
    
    t1.start();
    t2.start();
    Console Output
    Even Thread:: 0
    Odd Thread:: 1
    Even Thread:: 2
    Odd Thread:: 3
    Even Thread:: 4
    Odd Thread:: 5
    Even Thread:: 6
    Odd Thread:: 7
    Even Thread:: 8
    Odd Thread:: 9
    Even Thread:: 10
    Conclusion
    • From the odd() or even () method we have to first call notify or notifyAll() first.
    • Both odd() or even() method should be synchronized otherwise calling notifyAll() or wait() will throw exception

    Java Thread States

    A thread in Java at any point of time exists in any one of the 6 states. This article give a quick introduction of different Thread states and respective methods which results in threads state change.
    Following are the states of a Java Thread
    • New: Thre thread is just created by using start() method on the tread
    • Runnable: Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as a processor.
    • Blocked: A thread in the blocked state is waiting for a monitor lock
    • Waiting: A thread is in the waiting state due to calling one of the following methods:
      Object.wait() with no timeout
      Thread.join() with no timeout
      LockSupport.park
    • Timed Waiting: A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:Thread.sleep (long)
      Object.wait (long)
      Thread.join (long)
      LockSupport.parkNanos
      LockSupport.parkUntil
    • Terminated: The thread has completed execution

    Matrix Rotation in Java

    In this article, we will explore a few different ways to rotate a matrix clock by 90 degrees.

    Rotating Matrix to 90 Clockwise

    Following is our Matrix. 

    [    1        2        3    ]

    [    4        5        6    ]

    [    7        8        9    ]

    We will explore multiple ways to rotate this matrix clockwise 90 

    With Matrix Transpose

    Matrix transpose is a flipped version of the matrix along its diagonal. In short, it is the same as interchanging the rows with columns. For the above matrix the transposed matrix will look like. 

    [    1        4        7    ]

    [    2        5        8    ]

    [    3        6        9    ]

    Also, the transposed matrix is equivalent to 90 Left rotation of the original array.
    RoateMatrixWithTranspose
    Here the Rotation of the matrix is done in two steps
    1) We transpose the matrix 2) And we interchange the columns
    public void rotateMatrixRight90Transpose(int[][] mat) {
    
        int m = mat.length;
        int n = mat[0].length;
    
        for (int i = 0; i < m; i++) {
          for (int j = i; j < n; j++) {
            int x = mat[i][j];
            mat[i][j] = mat[j][i];
            mat[j][i] = x;
            System.out.println("IC" + i + ":" + j);
          }
        }
    
        // swap cols
        for (int i = 0; i < m; i++) {
          for (int j = 0; j < n / 2; j++) {
            // swap mat[i][j] with mat[N-i-1][j]
            int temp = mat[i][j];
            mat[i][j] = mat[i][n - j - 1];
            mat[i][n - j - 1] = temp;
          }
        }
      }
    Output

    Matrix Rotation with Transpose

    <= Original Matrix  =>

    [    1        2        3    ]

    [    4        5        6    ]

    [    7        8        9    ]



    <= After Transpose =>

    [    1        4        7    ]

    [    2        5        8    ]

    [    3        6        9    ]



    <= After Rotation =>

    [    7        4        1    ]

    [    8        5        2    ]

    [    9        6        3    ]

    Matrix Rotation in Single pass

    MatrixRotation.java
    The following code will rotate the matrix in a single pass.
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        for (int i = 0; i < (n + 1) / 2; i++) {
          for (int j = 0; j < n / 2; j++) {
            int temp = matrix[n - 1 - j][i];
            matrix[n - 1 - j][i] = matrix[n - 1 - i][n - j - 1];
            matrix[n - 1 - i][n - j - 1] = matrix[j][n - 1 - i];
            matrix[j][n - 1 - i] = matrix[i][j];
            matrix[i][j] = temp;
          }
        }
      }
    Output

    Matrix Rotation with single pass

    <= Original Matrix  =>

    [    1        2        3    ]

    [    4        5        6    ]

    [    7        8        9    ]



    <= After Rotation =>

    [    7        4        1    ]

    [    8        5        2    ]

    [    9        6        3    ]

    List All Files in a Directory in Java

    How to list all files in a directory in Java

    Say we want to get names of all the files under a directory and its subdirectories. Basically, we need to be able to look under each subdirectory and, if it has any files, add them to the result. This is a problem that can be solved recursively.
    In the following section, we have two different methods doing the same thing. Example 1 creates a File object with the given path and iterates over its contents. If the content is a file, we add it to the return list.

    Example 1: Get Files

    
    public List getFiles(String path) {
        List result = new ArrayList<>();
        File root = new File(path);
        File[] filesAndDirectories = root.listFiles();
    
        if (filesAndDirectories != null) {
            for (var file : filesAndDirectories) {
                if (file.isFile()) {
                    result.add(file.getName());
                } else if (file.isDirectory()) {
                    List subResult = getFiles(file.getPath());
                    result.addAll(subResult);
                }
            }
        }
        return result; 
    }
        
    In the second example, we are creating a Stream from the given path. Using functional programming (lambdas), we filter all the files from the stream and collect the file names in the returned list. We are using Files::isRegularFile method reference to invoke the static method isRegularFile.

    Example 2: Get All Files Using Files.walk

    
    public List getFiles(String path) throws IOException {
        Stream walk = Files.walk(Paths.get(path));
        List result = walk
            .filter(Files::isRegularFile)
            .map(x -> x.getFileName().toString())
            .collect(Collectors.toList());
    
        result.forEach(System.out::println);
        walk.close();
    
        return result;
    }
        

    Java Files.walk examples

    Java File.walk method is available in Java 8. It is very useful to traverse the content of a file tree. Walk goes in a depth-first fashion and returns a Stream object. We can then work with the stream to get the required result, like filtering only directories, finding files matching some name, etc. This article covers three examples of using File.walk to list all directories, files, and both.

    List all the folders

    List all the directories/folders inside the location specified by path.
    
    public List getFolders(String path) throws IOException {
        try (Stream walk = Files.walk(Paths.get(path))) {
            List result = walk.filter(Files::isDirectory)
                                      .map(x -> x.getFileName().toString())
                                      .collect(Collectors.toList());
            result.forEach(System.out::println);
            return result;
        }
    }
            

    List all files

    Similar to the above method, but here we filter only regular files with Files::isRegularFile.
    
    public List getFiles(String path) throws IOException {
        try (Stream walk = Files.walk(Paths.get(path))) {
            List result = walk.filter(Files::isRegularFile)
                                      .map(x -> x.getFileName().toString())
                                      .collect(Collectors.toList());
            result.forEach(System.out::println);
            return result;
        }
    }
            

    Files and Directories

    This method will list all directories along with files inside them. It is similar to the Linux command `ls *`.
    
    public List getFoldersAndFiles(String path) throws IOException {
        try (Stream walk = Files.walk(Paths.get(path))) {
            List result = walk.map(x -> {
                if (Files.isDirectory(x)) {
                    return x.getFileName().toString() + ":";
                } else {
                    return x.getFileName().toString();
                }
            }).collect(Collectors.toList());
            result.forEach(System.out::println);
            return result;
        }
    }
            

    References


    Table of Content

    Iterating Java Map

    Java Map is an object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. If we want to get the object stored at a particular key we can do so using the the get method.
    But if we want to traverse all the objects, then we have different ways of doing the same.

    Different Options

    In Java we have the following four options to iterate over java map.
    Map Iterator
    Classic way of using the Iterator of the keySet.
    //Iterator
    Map map = new TreeMap();
    System.out.println("Print using Iterator");
    Iterator it = map.keySet().iterator();
    
    while (it.hasNext()) {
      Integer k = it.next();
      String  v = map.get(k);
      System.out.print( "Key=" + k + " Value=" + v + "  ");
    }
    
    Java 8 forEach
    We can use the forEach introduced in Java 8 to iterate over key and value.
    //forFeach
    Map map = new TreeMap();
    System.out.println("\nPrint using Java 8 forEach");
    map.forEach((k,v) -> System.out.print("Key=" + k + " Value=" + v + "  "));
    For loop over the keyset
    Using for loop over the key set, and then getting the respective value from the map.
    //For loop over the keySet
    Map map = new TreeMap();
    System.out.println("\nPrint using for loop");
    for (Integer k : map.keySet()) {
      String  v = map.get(k);
      System.out.print("Key=" + k + " Value=" + v + "  ");
    }

    Full Example

    Full Java Class with all the above options to iterate over map.
    MapIterationExample
    package bootng.com.learn.collections;
    
    public class MapIterationExample {
      public static void main(String[] args) {
        Map<Integer, String> map = new TreeMap<Integer, String>();
        map.put(1, "A");
        map.put(3, "C");
        map.put(2, "B");
        map.put(4, "D");
        map.put(5, "E");
    
        // Iterator
        System.out.println("Print using Iterator");
        Iterator<Integer> it = map.keySet().iterator();
    
        while (it.hasNext()) {
          Integer k = it.next();
          String v = map.get(k);
          System.out.print("Key=" + k + " Value=" + v + "  ");
        }
    
        // forFeach
        System.out.println("\nPrint using Java 8 forEach");
        map.forEach((k, v) -> System.out.print("Key=" + k + " Value=" + v + "  "));
    
        // For loop over the keySet
        System.out.println("\nPrint using for loop");
        for (Integer k : map.keySet()) {
          String v = map.get(k);
          System.out.print("Key=" + k + " Value=" + v + "  ");
        }
    
        // Stream
        System.out.println("\nPrint using stream");
        map.keySet().stream().forEach(key -> {
          System.out.print("Key=" + key + " Value=" + map.get(key) + "  ");
        });    
      }
    }
    
    Output
    Print using Iterator
    Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  
    Print using Java 8 forEach
    Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  
    Print using for loop
    Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  
    Print using stream
    Key=1 Value=A  Key=2 Value=B  Key=3 Value=C  Key=4 Value=D  Key=5 Value=E  

    The char data type is a single 16-bit Unicode character. If we need to know the unicode value represented by the character we have several options. Following covers some of the options
    To get Unicode of a character
    If we want to know the unicode value for '1', we can use Integer.toString()
    char myChar = '1';
    String unicode = Integer.toString(myChar);
    System.out.print(unicode); // Prints 49
    To get Unicode of a character of a String
    If we want to know the unicode value for "1", we can use Integer.toString()
    String inputString = "1";
    int unicodeFromString = inputString.codePointAt(0);
    System.out.print(unicodeFromString); // Prints 49

    How to use ArrayDeque as Stack and Queue in Java

    The name Deque is short for "double ended queue" and is usually pronounced "deck". ArrayDeque is an implementation of the Deque interface. Since Deque supports adding and removing objects from both ends, it can be used as both Stack (LIFO) and Queue (FIFO). The Deque interface extends Queue.

    ArrayDeque As Stack

    Example 1
    Following code shows how to use Deque as a Stack. We use the push method to add items on top of the stack, resulting in the last item being taken out (LIFO).
    Deque<String> stack = new ArrayDeque<>();
    
    // push items to stack
    stack.push("Transformers (2007)");
    stack.push("Transformers: Revenge of the Fallen (2009)");
    stack.push("Transformers: Dark of the Moon (2011)");
    stack.push("Transformers: Age of Extinction (2014)");
    stack.push("Transformers: The Last Knight (2017)");
    stack.push("Bumblebee (2018)");
    
    // Size of the stack
    System.out.println("Size of the stack = " + stack.size());
    
    // Peek the top of the stack
    System.out.println("Peek top of the stack = " + stack.peek());
    
    // Pop the top of the stack
    System.out.println("Pop top of the stack = " + stack.pop());
    
    // Print entries of the Stack
    System.out.println("Entries in the Stack");
    stack.forEach(System.out::println);
    
    // Print entries of the Stack Using Iterator
    System.out.println("Entries in the Stack Using Iterator");
    Iterator<String> it2 = stack.iterator();
    while (it2.hasNext()) {
      String item = it2.next();
      System.out.println(item);
    }
    

    ArrayDeque as Queue

    Example 2
    Following example shows using ArrayDeque as a queue. We use the offer method to add items to the end of the list, making it FIFO.
    Queue<String> queue = new ArrayDeque<>();
    
    // add items to queue
    queue.offer("Transformers (2007)");
    queue.offer("Transformers: Revenge of the Fallen (2009)");
    queue.offer("Transformers: Dark of the Moon (2011)");
    queue.offer("Transformers: Age of Extinction (2014)");
    queue.offer("Transformers: The Last Knight (2017)");
    queue.offer("Bumblebee (2018)");
    
    // Size of the queue
    System.out.println("Size of the queue = " + queue.size());
    
    // Peek the front of the queue
    System.out.println("Peek front of the queue = " + queue.peek());
    
    // Poll the front of the queue
    System.out.println("Poll front of the queue = " + queue.poll());
    
    // Print entries of the queue
    System.out.println("Entries in the Queue");
    queue.forEach(System.out::println);
    
    // Print entries of the Queue Using Iterator
    System.out.println("Entries in the Queue Using Iterator");
    Iterator<String> it2 = queue.iterator();
    while (it2.hasNext()) {
      String item = it2.next();
      System.out.println(item);
    }
    
    Full Example ArrayDequeExample.java
    Following code contains the full class ArrayDequeExample
    import java.util.ArrayDeque;
    import java.util.Deque;
    import java.util.Iterator;
    import java.util.Queue;
    
    public class ArrayDequeExample {
    
      public static void main(String[] args) {
        ArrayDequeExample example = new ArrayDequeExample();
    
        example.asStack();
        example.asQueue();
      }
    
      private void asStack() {
        System.out.println(" ==========================");
        Deque<String> stack = new ArrayDeque<>();
    
        stack.push("Transformers (2007)");
        stack.push("Transformers: Revenge of the Fallen (2009)");
        stack.push("Transformers: Dark of the Moon (2011)");
        stack.push("Transformers: Age of Extinction (2014)");
        stack.push("Transformers: The Last Knight (2017)");
        stack.push("Bumblebee (2018)");
    
        System.out.println("Size of the stack = " + stack.size());
        System.out.println("Peek top of the stack = " + stack.peek());
        System.out.println("Pop top of the stack = " + stack.pop());
    
        System.out.println("Entries in the Stack");
        stack.forEach(System.out::println);
    
        System.out.println("Entries in the Stack Using Iterator");
        Iterator<String> it2 = stack.iterator();
        while (it2.hasNext()) {
          System.out.println(it2.next());
        }
      }
    
      private void asQueue() {
        System.out.println(" ==========================");
        Queue<String> queue = new ArrayDeque<>();
    
        queue.offer("Transformers (2007)");
        queue.offer("Transformers: Revenge of the Fallen (2009)");
        queue.offer("Transformers: Dark of the Moon (2011)");
        queue.offer("Transformers: Age of Extinction (2014)");
        queue.offer("Transformers: The Last Knight (2017)");
        queue.offer("Bumblebee (2018)");
    
        System.out.println("Size of the queue = " + queue.size());
        System.out.println("Peek front of the queue = " + queue.peek());
        System.out.println("Poll front of the queue = " + queue.poll());
    
        System.out.println("Entries in the Queue");
        queue.forEach(System.out::println);
    
        System.out.println("Entries in the Queue Using Iterator");
        Iterator<String> it2 = queue.iterator();
        while (it2.hasNext()) {
          System.out.println(it2.next());
        }
      }
    }
    

    Summary

    • Stack is a data structure that follows LIFO (Last In, First Out).
    • Queue is a data structure that follows FIFO (First In, First Out).
    • Deque allows adding and removing items from both ends.
    • Deque<E> is an interface in Java, with ArrayDeque and LinkedList as common implementations.

    Traverse a Map in Java

    Map is an interface and is a part of the java collections framework. Java collections framework provides a number of Map implementations like HashMap, TreeMap, LinkedHashMap etc. This post contains different ways of traversing through a HashMap, which are given below: Following section illustrates different ways to traverse the map data. Since map contains key-value data, most of them traverse through the keys and get the corresponding data.

    Map initialization

    Map initialization
    Following code creates instance of a TreeMap and puts 5 key-value pairs to it.
    Map map = new TreeMap();
    map.put(1,"A");
    map.put(3,"C");
    map.put(2,"B");
    map.put(4,"D");
    map.put(5,"E");
    Iterator
    Traverse using Iterator of the key set.
    System.out.println("Print using Iterator");
    Iterator it = map.keySet().iterator();
    
    while (it.hasNext()) {
      Integer k = it.next();
      String  v = map.get(k);
      System.out.print( "Key=" + k + " Value=" + v);
    }
    Forloop
    Following code traverse the map by using a for loop on the key set.
    //For loop over the keySet
    System.out.println("\nPrint using for loop");
    for (Integer k : map.keySet()) {
      String  v = map.get(k);
      System.out.print( "Key=" + k + " Value=" + v);
    }
    Stream
    Following code traverse the map using a stream on the key set.
    System.out.println("\nPrint using stream");
    map.keySet().stream().forEach(key -> {System.out.print ("Key=" + key + " Value=" + map.get(key)); });
    forEach
    Following code traverse using forEach method. forEach method was introduced in java 8.
    System.out.println("\nPrint using forEach");
    map.forEach((k, v) ->System.out.print( "Key=" + k + " Value=" + v)) ;

    Summary

    In this article we came across different ways we can iterate over Java Map.

    LinkedHashMap

    LinkedHashMap in Java stores key-value pairs and maintains the order of elements inserted. LinkedHashMap extends HashMap. The method removeEldestEntry in LinkedHashMap is used to delete the old entry in the map automatically. This method is triggered when we put values to the map.
    removeEldestEntry() method is triggered when we put new items to map. It is a boolean method and accepts one parameter. We can override this method to decide whether and when to remove eldest entries from the map.

    removeEldestEntry : What it does

    Say we want to only keep a certain number of items in the LinkedHashMap, and when it reaches the upper limit we want to get rid of the oldest entries. We could write a custom method to delete the oldest entry when map.size() == upper_limit and call it before adding any items. removeEldestEntry does the same thing, allowing us to implement this logic without boilerplate code.
    removeEldestEntry is checked by Java before adding any items to the map.
    
    LinkedHashMap map;
    map = new LinkedHashMap(10, 0.7f, false);
    map.put(0, "A"); 
    map.put(1, "B"); 
    map.put(2, "C"); 
    map.put(3, "D"); 
    map.put(4, "E"); 
    map.put(5, "F");
    
    System.out.println(map); // {0=A, 1=B, 2=C, 3=D, 4=E, 5=F}
          

    Example 2 : LinkedHashMap with removeEldestEntry

    In the following example, we want to keep only 4 items in the map. When it exceeds 4, the oldest entries should be deleted.
    
    LinkedHashMap map;
    
    map = new LinkedHashMap(10, 0.7f, false) {
      protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > 4;
      }
    };
    
    map.put(0, "A"); 
    map.put(1, "B"); 
    map.put(2, "C"); 
    map.put(3, "D"); 
    map.put(4, "E"); 
    map.put(5, "F");
    
    System.out.println(map); // {2=C, 3=D, 4=E, 5=F}
          
    Summary
    • removeEldestEntry by default returns false, meaning it will not remove any old items.
    • We can implement this method to delete older records.
    • removeEldestEntry is invoked while adding items to the map.
    • It is useful for implementing data structures similar to a cache.