Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Java

List and Map

What do List and Map hold, and how do you get things out?

A container that holds several values is called a collection. A List holds values in a line, in the order you put them in, and you get them out by an index that starts at 0. A Map holds keys paired with values, and you get a value out by its key. In code, as in List<String> names = new ArrayList<>();, you write the kind of container on the left (the part in angle brackets is the kind of value it holds), and the new on the right creates an empty container. You do not write a size in the parentheses. The number of stored items grows as you put things in with add or put. In this lab you switch between List and Map, and the same shape of code is compiled and run, and you see what is printed when you get something that is stored, when you get something that is not stored, and when you put the same thing in once more. (The number of stored items is printed first so that you can see it even when the program stops while getting.)

Checked against real execution · Compiled 6 combinations with javax.tools on JDK 21, ran them as child java processes, and checked the standard output, the standard error, and the exit code

Concepts in this lab

List, Set, Map
These are the three basic kinds of Java collections. A List is ordered, allows duplicates, and is accessed by index. A Set does not allow duplicates. A Map stores key-value pairs, and its keys cannot be duplicated. You choose among them by the nature of the data (whether order is needed, whether duplicates are allowed, and whether you look things up by key).
List add() and get()
A List is a container that holds values in a line, in the order you put them in, and each stored value is identified by an integer index that starts at 0. add(value) attaches the value to the end of the List, and get(index) returns the value at that index. A List can hold the same value several times, so adding the same value again stores one more at a different index. size() returns the number of stored values, and the indexes you can use are 0 up to size() - 1. ArrayList is a class built by the rules of List. It grows the array it uses inside by itself as you add values, so you do not have to decide a size when you create it.
Map put() and get()
A Map is a container that holds keys paired with values, and you get a value out by its key, not by an index. One Map cannot have two of the same key, and one key is paired with one value. put(key, value) pairs a key with a value, and if that key is already stored, it does not create a new pair but replaces the old value with the new one and returns the old value. get(key) returns the value paired with that key, and returns null without an exception if there is no paired value. In a Map that can also store null as a value, get returning null may not mean that the key is absent, and you check whether the key exists separately with containsKey. HashMap is a class built by the rules of Map, and it does not guarantee the order in which things come out.
IndexOutOfBoundsException
IndexOutOfBoundsException is the exception that is thrown when you refer to something by an index, such as an array, a string, or a List, and the index is out of range. The get(index) of a List throws this exception if the index is less than 0 or greater than or equal to the number of stored values. It is a subclass of RuntimeException. Code with a wrong index still compiles, and the exception is thrown when that line runs.

Try these

Running with the default settings

  1. You run it with java Main. The first line of main, List<String> names = new ArrayList<>();, runs. The List<String> on the left means "a List that holds strings (String)," and it decides what kind of container the variable names refers to. The new ArrayList<>() on the right creates an empty List with nothing in it, and names refers to that List. List is the name of the rules for holding values, and ArrayList is a real class built by those rules. No size is written in the parentheses. The number of stored values is 0.
  2. The line names.add("kim"); runs. add attaches a value to the end of the List. It was empty, so "kim" goes in at index 0. Indexes start at 0 and are numbered in the order you put values in. The number of stored values is 1.
  3. The line names.add("lee"); runs. add attaches a value to the end of the List. "lee" goes in at index 1, right after "kim". The number of stored values is 2.
  4. The line System.out.println(names.size()); prints the number of stored values. The number printed is 2.
  5. At the line System.out.println(names.get(0));, the call get(0) returns the value at index 0, and println prints "kim". The index to get is the 0 written in the parentheses. Getting a value does not remove it from the List, so the number of stored values stays 2.
  6. The last line of main runs and the program ends.

Result of this run

Code

// Import java.util, which contains the collection classes
import java.util.*;

public class Main {
    public static void main(String[] args) {
        // List: a container that holds values in a line, in the order you put them in. It starts out empty
        List<String> names = new ArrayList<>();
        // Put in: add attaches the value to the end. Indexes are numbered from 0
        names.add("kim");
        names.add("lee");
        // Count: size returns the number of stored values
        System.out.println(names.size());
        // Get: get returns the value at that index
        System.out.println(names.get(0));
    }
}

Assumptions of this model

The compiler and runtime are JDK 21.0.12.1 (javac 21). All 6 combinations were checked against real runs: the same source as the code on the screen (identical line by line) was compiled with javax.tools and all of them compiled, and the compiled Main was run by starting the java of this JDK as a child process, and the standard output, the standard error, and the exit code were captured. What was checked is whether compilation succeeded, the lines of the standard output (the number stored and the value retrieved), and the exit code and the first line of the standard error (the combination that throws an exception had exit code 1 and the first line Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 5 out of bounds for length 2, followed by a stack trace with Main.main in the standard error, and the others had exit code 0 and an empty standard error). The facts that the step sentences rely on were checked by running separate source in the same way. In the List, "kim" and "lee" are stored at indexes 0 and 1 (the indexOf results were 0 and 1), the number stored stays 2 after a get, and putting the same "kim" in again stores it separately at index 2 (get(2) was kim, and the count was 3). In the Map, calling put with the same key returns the old value 20 and the value becomes 25 with the pairs staying at 2, and for the key park, which was not stored, get is null and containsKey is false. For the documentation, I opened the Java SE 21 API documentation myself. That indexes in a List start at 0 and that a List can hold the same value several times, that add attaches to the end, and that get throws an IndexOutOfBoundsException for an index out of range follow java.util.List and java.util.ArrayList; that an ArrayList grows its capacity by itself as you add follows java.util.ArrayList; that a Map cannot have two of the same key, that get returns null when there is no pair, and that put replaces the old value and returns it follow java.util.Map and java.util.HashMap; that IndexOutOfBoundsException is a subclass of RuntimeException follows java.lang.IndexOutOfBoundsException; and that the length of an array does not change after it is created follows section 10.2 of the Java Language Specification (Java SE 21). I opened these documents in a way that returned summaries of their content, so I did not read every word of the original text myself. That the code compiles even with a wrong index and that the exception is thrown at run time, and the exit code 1 and the text in the standard error, were not taken from the documentation but observed with this java. The code on the screen has exactly the shape that is run with java Main, and there is no package. The number stored is printed first and the line that gets comes after it so that, even in the combination that stops while getting, the number stored can be checked in the output. The dashed slots in the diagram (index 5, key park) are drawn to point to a position where nothing is stored, and they do not mean that a real List or Map has such a slot. Other methods of List and Map (remove, contains, and so on), ways to go through all the items, Set, how the order of retrieval is decided, and storing null as a value are not covered. The difference between ArrayList and LinkedList is covered in the in-depth lab "ArrayList and LinkedList", how HashMap finds a key in "Inside HashMap", and the order of the kinds of Set and Map in "Kinds of Set and Map".

Previous lab: Generics · Next lab: Lambdas

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these