Collections in Java are mainly concentrated in two parts, one is in the java.util package, and the other is in java.util.concurrent. The latter is based on the former and defines some collections that implement synchronization functions.
This article mainly focuses on various collection objects under java.util. Collection objects in Java can be roughly divided into three categories: List, Set and Map. The corresponding UML diagram is as follows (including most collection objects under java.util):
Collection overview
Both List and Set in Java collections come from Collection. It is a good entry point for learning collections. It includes operations that are usually required in collections:
Add elements: add/addAll
Clear the collection: clear
Remove elements: remove/removeAll
Determine whether the collection contains an element: contains/containsAll
Determine whether the collection is empty: isEmpty
Calculate the number of elements in a collection: size
Convert a collection to an array: toArray
Get iterator: iterator
Let's look at a simple example. The following code will return a collection whose elements are randomly generated integers:
return collection;
}
1) Use iterators to traverse the collection. As mentioned when describing the Collection interface above, all collections will have an iterator that we can use to traverse the collection.
List in Java is an effective extension of array. It is a structure that can hold elements of any type if generics are not used. If generics are used, it can only hold elements of the type specified by the generics. Compared with arrays, the capacity of List can be dynamically expanded.
The elements in the List can be repeated, and the elements inside are "ordered". The "ordered" here does not mean sorting, but means that we can specify the position of an element in the collection.
Commonly used collection objects in List include: ArrayList, Vector and LinkedList, the former two are stored based on arrays, and the latter are stored based on linked lists. Among them, Vector is thread-safe, and the other two are not thread-safe.
List can contain null, even if generics are used.
ArrayList may be the most commonly used collection object. In the above example code, we also use it to instantiate a Collection object, so we won’t go into details here.
Vector
An example of Vector is as follows. First we look at how to generate and output Vector:
[9, 29, 32, 54, 12]
size of vector is 3
[29, 32, 54]
LinkedList uses linked lists to store data. Its sample code is as follows:
The output is as follows:
null
null
null
size of linked list is 8
[100, 84, 19, 57, 68, 26, 27, 47]
Set is similar to List, both are used to store a single element, and the number of individual elements is uncertain. But Set cannot contain duplicate elements. If two identical elements are inserted into Set, the latter element will not be inserted.
Set can be roughly divided into two categories: unsorted Set and sorted Set. Unsorted Set includes HashSet and LinkedHashSet, and sorted Set mainly refers to TreeSet. Among them, HashSet and LinkedHashSet can contain null.
HashSet
HashSet is a collection backed by a Hash table, which is not thread-safe.
Let's look at the following example, which is basically the same as the first example with Vector:
for (int i = 0; i < 3; i++)
{
set.add(new Integer(100));
}
set.add(null);
System.out.println("size of set is " + set.size());
System.out.println(set);
}
classMyInteger
{
private Integer value;
public MyInteger(Integer value)
{
this.value = value;
}
public String toString()
{
return String.valueOf(value);
}
public int hashCode()
{
return 1;
}
public boolean equals(Object obj)
{
return true;
}
}
The following is the corresponding test method:
for (int i = 0; i < 3; i++)
{
set.add(new MyInteger(100));
}
System.out.println("size of set is " + set.size());
System.out.println(set);
}
TreeSet is a Set that supports sorting, and its parent interface is SortedSet.
Let's first take a look at the basic operations of TreeSet:
Random r = new Random();
for (int i = 0; i < 5; i++)
{
set.add(new Integer(r.nextInt(100)));
}
System.out.println(set);
System.out.println(set.first());
System.out.println(set.last());
System.out.println(set.descendingSet());
System.out.println(set.headSet(new Integer(50)));
System.out.println(set.tailSet(new Integer(50)));
System.out.println(set.subSet(30, 60));
System.out.println(set.floor(50));
System.out.println(set.ceiling(50));
}
[53, 49, 48, 42, 8]
[8, 42, 48, 49]
[53]
[42, 48, 49, 53]
Next, we first redefine Integer:
public MyInteger2(int value)
{
this.value = value;
}
public int compareTo(Object arg0)
{
MyInteger2 temp = (MyInteger2)arg0;
if (temp == null) return -1;
if (temp.value > this.value)
{
return 1;
}
else if (temp.value < this.value)
{
return -1;
}
return 0;
}
public boolean equals(Object obj)
{
return compareTo(obj) == 0;
}
public String toString()
{
return String.valueOf(value);
}
}
Map stores "key-value pairs". Similar to Set, there are two types of Maps in Java: sorted and unsorted. Unsorted include HashMap, Hashtable and LinkedHashMap, and sorted include TreeMap.
Unsorted Map
Both HashMap and Hashtable are stored in the form of Hash tables. HashMap is not thread-safe, but Hashtable is thread-safe. We can regard HashMap as a "simplified" version of Hashtable.
HashMap can store null, whether for Key or Value. Hashtable cannot store null.
Regardless of HashMap or Hashtable, if we observe its constructor, we will find that it can have two parameters: initialCapacity and loadFactor. By default, initialCapacity is equal to 16 and loadFactor is equal to 0.75. This is related to the number of elements that can be stored in the Hash table. When the number of elements exceeds initialCapacity*loadFactor, the rehash method will be triggered to expand the hash table. If we need to insert too many elements into it, we need to adjust these two parameters appropriately.
Let’s first look at an example of HashMap:
map.put(new Integer(1), "a");
map.put(new Integer(2), "b");
map.put(new Integer(3), "c");
System.out.println(map);
System.out.println(map.entrySet());
System.out.println(map.keySet());
System.out.println(map.values());
}
map.put(null, null);
map.put(null, null);
map.put(new Integer(4), null);
map.put(new Integer(5), null);
System.out.println(map);
System.out.println(map.entrySet());
System.out.println(map.keySet());
System.out.println(map.values());
}
table.put(new Integer(1), "a");
table.put(new Integer(2), "b");
table.put(new Integer(3), "c");
System.out.println(table);
System.out.println(table.entrySet());
System.out.println(table.keySet());
System.out.println(table.values());
}
private static void hashTableTest2()
{
Map<Integer,String> table = new Hashtable<Integer, String>();
table.put(null, null);
table.put(null, null);
table.put(new Integer(4), null);
table.put(new Integer(5), null);
System.out.println(table);
System.out.println(table.entrySet());
System.out.println(table.keySet());
System.out.println(table.values());
}
Sorting Map mainly refers to TreeMap, which has a time complexity of O(log(n)) when adding, deleting, and searching elements. It is not thread safe.
Its characteristics are very similar to TreeSet, so I won’t go into details here.