Sie sind auf Seite 1von 1

Sign in Get started

ARCHIVE WRIT E FOR US S T YLE GUIDE ABOUT JOB BOARD

You have 2 free stories left this month. Sign up and get an extra one for free.

Utility Classes of the JDK: Collections


and Arrays
Some hidden little gems you might not know about
Ben Weidig Follow
Mar 10 · 6 min read

Photo by Thomas Ciszewski on Unsplash

The JDK is evolving with every new release, adding more and improving
existing features. Beneath the surface are hidden gems that can make
our lives as developers much easier.

Missing pieces of functionality are often complemented by third-party-


libraries, like the different Apache Commons libraries, or Google Guava.
But over time, some of their functionality and ideas become incorporated
into the JDK.

The first article highlights the utility classes with their static methods for
dealing with collections and arrays.

At least Java 8 is assumed. Some methods might not be available in earlier


versions. All listed methods omit the static keyword and generic type
definitions to reduce visual clutter. Every method is linked to the Java
Platform SE 8 documentation provided by Oracle.

. . .

Working with Collections


The utility class java.util.Collections , introduced with Java 2, and
improved with generics thanks to Java 5, provides a lot of static methods
to operate on or return collections.

Immutable empty collections


When we need to return an empty collection, or a collection-related
type, we could create a new empty instance. If our code design allows
this instance to be immutable, we can use Collections instead for an
empty, static instance:

Set<T> emptySet()

List<T> emptyList()

Map<K,V> emptyMap()

SortedSet<E> emptySortedSet()

SortedMap<K,V> emptySortedMap()

NavigableSet<E> emptyNavigableSet()

NavigableMap<K,V> emptyNavigableMap()

Enumeration<T> emptyEnumeration()

Iterator<T> emptyIterator()

ListIterator<T> emptyListIterator()

Singletons
Instead of an empty collection, we can also return an immutable
collection with exactly one element:

Set<T> singleton(T o)

List<T> singletonList(T o)

Map<K,V> singletonMap(K key,


V value)

Immutability
Creating an unmodifiable view backed by an existing collection. This way
we can make a pre-existing collection immutable:

Collection<T> unmodifiableCollection(Collection<? extends T> c)

Set<T> unmodifiableSet(Set<? extends T> s)

List<T> unmodifiableList(List<? extends T> list)

Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m)

SortedSet<T> unmodifiableSortedSet(SortedSet<T> s)

SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,? extends V> m)

NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s)

NavigableMap<K,V> unmodifiableNavigableMap(NavigableMap<K,? extends


V> m)

Sorting and (re)ordering


Sorting a given collection by either natural order, or uses the provided
Comparator :

void sort(List<T> list)

void sort(List<T> list,


Comparator<? super T> c)

Non-sort-related (re-)ordering is also supported, like reversing the


order, rotating or moving all elements around, and randomly shuffling
the content:

void reverse(List<?> list)

void rotate(List<?> list,


int distance)

void shuffle(List<?> list)

void shuffle(List<?> list,


Random rnd)

Binary search
Instead of iterating over collections, the index of a specific element can
be located using the binary search algorithm:

int binarySearch(List<? extends Comparable<? super T>> list,


T key)

int binarySearch(List<? extends T> list,


T key,
Comparator<? super T> c)

Thread-safety
Creating a synchronized (thread-safe) view of an existing collection:

Collection<T> synchronizedCollection(Collection<T> c)

Set<T> synchronizedSet(Set<T> s)

List<T> synchronizedList(List<T> list)

Map<K,V> synchronizedMap(Map<K,V> m)

SortedSet<T> synchronizedSortedSet(SortedSet<T> s)

SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s)

NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m)

To remain thread-safe, all access to the backing collection must be by the


returned synchronized collection.

Another restriction is the need for manual synchronization if the


collection is traversed by an Iterator , Spliterator , or Stream . The
creation of the traversal-object must be inside a synchronized block:

1 List<String> threadSafe =
2 Collections.synchronizedCollection(data);
3
4 synchronized (threadSafe) {
5 // This call MUST be inside a synchronized block
6 Iterator<String> i = c.iterator();
7 while (i.hasNext()) {
8 // ...
9 }
10 }

medium-2020-utility-classes-collections-arrays-01.java hosted with ❤ by GitHub view raw

Type-safe non-generic collections


Before the introduction of generics, collection types had to deal with the
lack of type-safety and everything was an Object . If we have legacy code
with such a non-generic collection, we can create a type-safe view of that
collection:

Collection<E> checkedCollection(Collection<E> c,
Class<E> type)

Set<E> checkedSet(Set<E> s,
Class<E> type)

List<E> checkedList(List<E> list,


Class<E> type)

Map<K,V> checkedMap(Map<K,V> m,
Class<K> keyType,
Class<V> valueType)

Queue<E> checkedQueue(Queue<E> queue,


Class<E> type)

SortedSet<E> checkedSortedSet(SortedSet<E> s,
Class<E> type)

SortedMap<K,V> checkedSortedMap(SortedMap<K,V> m,
Class<K> keyType,
Class<V> valueType)

NavigableSet<E> checkedNavigableSet(NavigableSet<E> s,
Class<E> type)

NavigableMap<K,V> checkedNavigableMap(NavigableMap<K,V> m,
Class<K> keyType,
Class<V> valueType)

Here’s a quick example how to use make a List type-safe:

1 // UNTYPED COLLECTION
2 List untyped = new ArrayList();
3 untyped.add("A");
4 untyped.add("B");
5 // untyped.add(1); <-- this would be valid, but is undesired
6
7 // CREATE TYPE-SAFE VIEW
8 List<String> typed = Collections.checkedList(untyped, String.class);

medium-2020-utility-classes-collections-arrays-02.java hosted with ❤ by GitHub view raw

. . .

Working with Arrays


The utility class java.util.Arrays is kind of the array-based counterpart
to java.util.Collections , providing static methods for operating on,
sorting, copying, searching arrays, etc.

Due to value-types, and the generality of Object , most methods are


available for value-types, specifically Object , and generics.

To not list every single method, the placeholder type[] will be used as a
stand-in for the different types. The type boolean is a special case and
won’t support a method unless it’s mentioned.

boolean[] <-- Only available if explicitly stated


byte[]
char[]
int[]
long[]
short[]
long[]
float[]
double[]
Object[]

List creation
The easiest way to create a list from an arbitrary amount of elements:

List<T> asList(T... a)

Thanks to the varargs , we can either provide multiple elements or an


array:

1 String[] array = new String[] { "DE", "EN" };


2
3 List<String> fromArray = Arrays.asList(array);
4
5 List<String> fromElements = Arrays.asList("DE", "EN");

medium-2020-utility-classes-collections-arrays-03.java hosted with ❤ by GitHub view raw

Be aware that the List instance will be immutable. To create a mutable


view again, we can wrap it in another ArrayList :

1 List<String> lang = Arrays.asList("DE", "EN");


2
3 lang.add("JP"); // throws UnsupportedOperationException
4
5 List<String> mutable = new ArrayList<>(lang);

medium-2020-utility-classes-collections-arrays-04.java hosted with ❤ by GitHub view raw

Sorting
Just like collections before, arrays can be sorted. In case of value types,
this means in numerical order, for Object and <T> , in the natural order.

void sort(type[] a)

void parallelSort(type[] a)

void parallelSort(T[] a)

Sorting only a specific range of an array is also supported:

void sort(type[] a,
int fromIndex,
int toIndex)

void sort(T[] a,
int fromIndex,
int toIndex, Comparator<? super T> c)

void parallelSort(type[],
int fromIndex,
int toIndex)

void parallelSort(T[] a,
int fromIndex,
int toIndex)

If natural order doesn’t suffice, a custom Comparator can be provided:

void sort(T[] a,
Comparator<? super T> c)

void sort(T[] a,
int fromIndex,
int toIndex,
Comparator<? super T> c)

void parallelSort(T[] a,
Comparator<? super T> cmp)

void parallelSort(T[] a,
int fromIndex,
int toIndex,
Comparator<? super T> cmp)

Streams
I have written multiple times about how much I love Streams. With the
help of Arrays we can easily create Stream<T> and value-type Streams, at
least for the supported types:

type[] | ValueTypeStream
----------|-----------------
int[] | IntStream
long[] | LongStream
double[] | DoubleStream

ValueTypeStream stream(type[] array)

ValueTypeStream stream(type[] array,


int startInclusive,
int endExclusive)

Stream<T> stream(T[] array)

Stream<T> stream(T[] array,


int startInclusive,
int endExclusive)

Spliterator
Java 8 introduced the java.util.Spliterator interface, a base utility for
Streams. It's used for traversing and partitioning sequences.

Spliterators are also subclassed according to their value-type, and as


before, only three numerical types are supported:

type[] | ValueTypeSpliterator
----------|---------------------
int[] | Spliterator.OfInt
long[] | Spliterator.OfLong
double[] | Spliterator.OfDouble

ValueTypeSpliterator spliterator(type[] array)

ValueTypeSpliterator spliterator(type[] array,


int startInclusive,
int endExclusive)

Spliterator<T> spliterator(T[] array)

Spliterator<T> spliterator(T[] array,


int startInclusive,
int endExclusive)

String representations
For better debugging or logging output, we can create a string
representation of arrays. In addition to the listed types above, boolean is
supported. Object[] might contain other arrays, so a method for a deep
string representation is also available:

String toString(type[] a)

String deepToString(Object[] a)

We should never use the string representation generated by a toString()

method for anything other than debugging or simple display purposes.


The actual implementation might change over time, or different JDKs
might handle it not quite exactly the same.

Equality
Like string representation, boolean is supported, and we can check
Object[] for deep equality:

boolean equals(type[] a,
type[] a2)

boolean deepEquals(Object[] a1,


Object[] a2)

Hashcodes
Calculating a hashcode also supports boolean and deep calculation:

int hashCode(type[] a,
type[] a2)

int deepHashCode(Object[] a1,


Object[] a2)

Binary search
Finds the index a specific element in an array using the binary search
algorithm:

int binarySearch(type[] a,
type key)

int binarySearch(type[] a,
int fromIndex,
int toIndex,
type key)

int binarySearch(T[] a,
T key,
Comparator<? super T> c)

int binarySearch(T[] a,
int fromIndex,
int toIndex,
T key,
Comparator<? super T> c)

Copying
We can copy any array to a specific length, either truncating it, or
padding the new space with the appropriate uninitialized value, or null .

The value type boolean is supported:

type[] copyOf(type[] original,


int newLength)

T[] copyOf(T[] original,


int newLength)

T[] copyOf(U[] original,


int newLength,
Class<? extends T[]> newType)

type[] copyOfRange(type[] original,


int from,
int to)

T[] copyOfRange(T[] original,


int from,
int to)

T[] copyOfRange(U[] original,


int from,
int to,
Class<? extends T[]> newType)

Filling and setting


Fill an array, or specified range, with a provided value. The value type
boolean is supported:

void fill(type[] a,
type val)

void fill(type[] a,
int fromIndex,
int toIndex,
type val)

If we need more control over the value, a generator function can be


provided:

type[] | ValueGenerator
----------|---------------------
int[] | IntUnaryOperator
long[] | IntToLongFunction
double[] | IntToDoubleFunction

void setAll(type[] array,


ValueGenerator generator)

void setAll(T[] array,


IntFunction<? extends T> generator)

void parallelSetAll(type[] array,


ValueGenerator generator)

void parallelSetAll(T[] array,


IntFunction<? extends T> generator)

Parallel prefixing
The parallelPrefixing methods cumulate each element of an array in
parallel. For larger arrays, this kind of operation is usually more efficient
than sequential processing:

type[] | ValueOperator
----------|---------------------
int[] | IntBinaryOperator
long[] | LongBinaryOperator
double[] | DoubleBinaryOperator

void parallelPrefix(type[] array,


ValueOperator op)

void parallelPrefix(T[] array,


BinaryOperator<T> op)

void parallelPrefix(type[] array,


int fromIndex,
int toIndex,
ValueOperator op)

void parallelPrefix(T[] array,


int fromIndex,
int toIndex,
BinaryOperator<T> op)

If you haven’t used this method before, it can be unclear what exactly it
does, at least that has been my experience. Here’s an example to explain
it:

1 // Sum up every element pair


2 int[] array = { 1, 2, 3, 4 };
3 Arrays.parallelPrefix(array, (lhs, rhs) -> lhs + rhs);
4
5 // Simplified view of what happened:
6 array[0] = 0 + array[0];
7 array[1] = array[0] + array[1];
8 array[2] = array[1] + array[2];
9 array[3] = array[2] + array[3];

medium-2020-utility-classes-collections-arrays-05.java hosted with ❤ by GitHub view raw

. . .

Conclusion
Many common tasks that we might either code ourselves, or use a third-
party-library, can be safely done directly with the JDK. This way we
depend on fewer externalities, don’t introduce bugs by writing additional
code and handle common tasks in a concise, consistent, and
reproducible way.

The next part will present utility classes for handling I/O.

. . .

Resources
java.util.Arrays

java.util.Collections

T hanks to Zack Shapiro.

Software Development Programming Java Android Mobile

94 claps

WRIT T EN BY

Ben Weidig Follow

Software developer, entrepeneur, blogger. Mostly Java,


sometimes Swift, Golang, Bash and all the other fun stu .

Better Programming Follow

Advice for programmers.

Write the rst response

More From Medium

How To Be a Developer Grokking Streams and Making Rust Projects Many-to-Many


T hat People Want on Fighting Zombies with Cargo Relationship Done Right
T heir Team Bogdan in T he Startup James Bowen in the Entity Framework:
T homas Guibert in Better Multi-Clients & Users
Programming T ika Pahadi

How to decouple Views Here Are the Most 7 Alternatives to the Web Applications using
from their State Interesting Developer <div> HT ML Tag Python and Django
Liviu Coman in Zero Equals Podcasts Zac Heisey Francisco Igor
False Indrek Lasn in Better
Programming

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. On Medium, smart Follow all the topics you care about, and we’ll deliver the Get unlimited access to the best stories on Medium — and
voices and original ideas take center stage - with no ads in best stories for you to your homepage and inbox. Explore support writers while you’re at it. Just $5/month. Upgrade
sight. Watch

About Help Legal

Das könnte Ihnen auch gefallen