<< Hide Menu
4 min readβ’june 18, 2024
Milo Chang
Milo Chang
TheΒ Java Collections FrameworkΒ is a set of different data structures used to store data. They consist of several types:Β sets, lists, deques, and maps. Each of these has subtypes, which are separate classes.Β
SetsΒ are data types where each item occurs only once, and the data is unordered.Β
ListsΒ are collections of items that can repeat, and the data is ordered.Β
DequesΒ are similar to lists but items can only be added or removed at the beginning and the end, not in the middle.Β
MapsΒ are pairs with a key and a value to represent pairs of items, such as a name and an address.
The main type of data structure that we are concerned with is lists. There are two main types of lists: LinkedLists and ArrayLists, which differ in their method of accessing elements.
With LinkedLists, we can only access elements in order. If we want to access the 8th element, we have to start with the first element and then traverse through the LinkedList in order.
On the other hand, with ArrayLists, we can access elements in the middle of the list much more easily, using a single method call, covered in Topic 7.2.
The Java Collections Framework, including ArrayLists, only accepts objects and reference types inside these collections and the system won't know which class the objects are until runtime. All the objects in the collection must be of a certain class. However, we can have a modifier <E> where E is a certain class which will signify the type of object in the ArrayList. For example, we can have <Integer>, <Double>, or <String>, among many other possibilities. Using the generic <E> will allow for type checking while the class is being compiled.
Before we can use ArrayLists, we need to import the ArrayList class with this import statement:
import java.util.ArrayList;
Unlike arrays, we can only create ArrayLists using a constructor and not with a pre-initialized ArrayList. The most basic constructor is this:
ArrayList list = new ArrayList();
However, we can use generics to specify the types of objects in the ArrayList. This is preferred for the compiler to find errors that they may not have found otherwise. This is done using the following:
ArrayList<E> list = new ArrayList<E>();
For example, if we wanted to create an ArrayList to store Integers, we would use:
ArrayList<Integer> integerList = new ArrayList<Integer>();
Alternatively, if we wanted to create an ArrayList to store Strings, we would use:
ArrayList<String> integerList = new ArrayList<String>();
In some ways, ArrayLists function a lot like arrays. As we'll cover in Topic 7.2:
You can access/change elements anywhere in an ArrayList
You can put new elements anywhere in an ArrayList
So you may be wondering, why would we even use ArrayLists when we can just make arrays that store integers, doubles, or Strings? The reason is size.
When we make an array, we have to declare its size. For example, to make an array for ten integers, we would have to write the one of the following:
int[] array = new int[10];
or
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Both of these fix the size of the array to ten integers. But what if we suddenly need to store 11 integers? We would need to create a completely new array.
In contrast, ArrayLists are much more dynamic. When we create an ArrayList for Integers, we just write:
ArrayList<Integer> integerList = new ArrayList<Integer>();
There is no set size for the integerList. We can keep adding as many integers as we need.
So in cases where you don't know how much data you'll be storing, ArrayLists are more flexible and don't require you to know how much data to store ahead of time.
It is important to note that Integer and Double are wrapper classes for the primitive data types int and double, respectively. You don't need to worry about this distinction too much when you write your code since Java will automatically convert back and forth between primitive data types and the wrapper classes (autoboxing and unboxing).
One of the benefits of using wrapper classes is that they allow primitive data types to be used in contexts where only objects are allowed, such as in the collections framework (e.g., in an ArrayList). For example, you can use an ArrayList<Integer> to store a list of integers, or an ArrayList<Double> to store a list of doubles.
However, using wrapper classes can have some drawbacks, especially when it comes to performance. Wrapper classes are generally slower and use more memory than their primitive counterparts. This is because they require additional memory to store the object-related information (such as the object header) in addition to the value being wrapped.
Therefore, if you are working with large amounts of data and need to optimize for performance, it may be more efficient to use a regular array of primitives (e.g., int[] or double[]) instead of an ArrayList of wrapper objects (e.g., ArrayList<Integer> or ArrayList<Double>).
Β© 2024 Fiveable Inc. All rights reserved.