Collections utility class java

Writing a Utility Class for Collections in Java 8

One of the fluent APIs that Java 8 brings us, is the Java 8 Stream API, which provides a practical and minimal interface to code, especially with the help of Java 8 Lambdas.

Today, we are going to write a simple utility class to convert and modify java collections with ease, by using the power of Java 8 Streams.

Utility Classes

Utility classes are structures that contain reusable and stateless helper methods. We implement these methods for handling any kind of specific operations for specific purposes. Because of their stateless nature, we mostly prefer to define them as static.

First of all, let’s define a simple class:

public class UtilsForCollections  >

Static Classes in Java

Static classes are classes that cannot be instantiated. As utility classes do not need to hold any state, it is appropriate to define them as static to prevent creating instances of them.

Unlike some other languages, in Java, we cannot use the static modifier for classes. Instead, we will use a private constructor to give the same ability to our utility classes:

public class UtilsForCollections  private UtilsForCollections()  > >

Array to Collection Conversion

The first method of our utility class will be a generic method that simply converts a given array structure to java.util.Collection type.

We have two different behavioral types to return as java collections, one of them is List that is used when we need to preserve the order of the elements, the other one is Set that is used when we need to preserve the uniqueness of the elements.

First, let’s define a generic method that handles array to List conversion:

public static T> ListT> toList(T[] array)  // TODO implement but how? >

Power of Java 8 Stream API

Normally to implement this kind of method, we need to traverse the elements of an array and populate each of them to a newly created ArrayList object. However, thanks to the Java 8 Stream API, we can easily get rid of this sort of boilerplates.

So let’s implement our toList method:

public static T> ListT> toList(T[] array)  return Arrays.stream(array).collect(Collectors.toList()); >

We use the Arrays.stream() method to open a stream over the given array. Once we acquire the stream instance, we may operate over the stream by many provided methods like collect, filter, map, etc. We choose the method collect here to copy elements from an array to another structure with the help of predefined stream collectors.

Like toList method, let’s define a separate method for array to Set conversion:

public static T> SetT> toSet(T[] array)  return Arrays.stream(array).collect(Collectors.toSet()); >

Handling Primitive Types

With the help of generics we successfully handled for all object types but when it comes to primitive types of java we cannot use our generic methods. We see an error when we try to use with primitive-typed arrays and our java compiler complains about the argument types which are not applicable:

int[] intArray = new int[]  1, 2, 3 >; UtilsForCollections.toList(intArray); // this line gives us a compile error!

One of the ways of solving this problem is simply defining separate methods with primitive-typed arguments. We will use boxed method of streams to box every primitive element to its wrapper objects:

public static ListInteger> toList(int[] array)  return Arrays.stream(array).boxed().collect(Collectors.toList()); > public static ListLong> toList(long[] array)  return Arrays.stream(array).boxed().collect(Collectors.toList()); > public static ListDouble> toList(double[] array)  return Arrays.stream(array).boxed().collect(Collectors.toList()); >

Similarly, we can define more methods in the same way for other remaining primitives like boolean, byte, char, short, float, etc.

And also we can define their Set versions that are pretty same:

public static SetInteger> toSet(int[] array)  return Arrays.stream(array).boxed().collect(Collectors.toSet()); > public static SetLong> toSet(long[] array)  return Arrays.stream(array).boxed().collect(Collectors.toSet()); > public static SetDouble> toSet(double[] array)  return Arrays.stream(array).boxed().collect(Collectors.toSet()); >

Ordered Sets

Sometimes it might be important to preserve both the order and the uniqueness of the elements and we need to handle this with a single collection type. If we encounter this problem in java the LinkedHashSet collection type comes to rescue.

Let’s add an optional parameter to our ToSet method in order to return LinkedHashSet type instead of unordered HashSet:

public static T> SetT> toSet(T[] array)  return UtilsForCollections.toSet(array, false); > public static T> SetT> toSet(T[] array, boolean preserveOrder)  if (preserveOrder)  return Arrays.stream(array) .collect(Collectors.toCollection(LinkedHashSet::new)); > return Arrays.stream(array).collect(Collectors.toSet()); >

The former method here simply uses the overloaded method of itself. By doing this, we not only provide a default value for preserveOrder parameter but also protect the backward compatibility of our utility methods. We set false to preserveOrder as default value here.

Collection to Collection Conversions

Conversion from a collection type to another collection type is also easily possible with streams. We can get streams from collections as well and we can perform List to Set conversion and vice versa.

Let’s define some methods to add this ability to our utility class:

public static T> ListT> toList(CollectionT> collection)  return collection.stream().collect(Collectors.toList()); > public static T> SetT> toSet(CollectionT> collection)  return UtilsForCollections.toSet(collection, false); > public static T> SetT> toSet(CollectionT> collection, boolean preserveOrder)  if (preserveOrder)  return collection.stream() .collect(Collectors.toCollection(LinkedHashSet::new)); > return collection.stream().collect(Collectors.toSet()); >

Filtering Arrays and Collections

One of the handy methods of Stream API is filter method. This provides a comfortable way of filtering an array or collection and creating subsets of theirs. With the power of lambdas we can also customize the behavior.

Let’s define two methods to perform filtering on arrays or collections:

public static T> ListT> filterArray(T[] array, Predicate super T> predicate)  return Arrays.stream(array).filter(predicate) .collect(Collectors.toCollection(ArrayList::new)); > public static T> ListT> filterCollection(CollectionT> collection, Predicate super T> predicate)  return collection.stream().filter(predicate) .collect(Collectors.toCollection(ArrayList::new)); >

Next, let’s use this method to filter an array of strings by their first letters as the character ” a “:

String[] array = new String[]  "apple", "banana", "orange", "avocado", "mango" >; ListString> filtered = UtilsForCollections.filterArray(array, v -> v.startsWith("a")); filtered.forEach(System.out::println);

Now, by running this code, we will see the outputs of the filtered elements:

Concatenate Elements into a String

Another ability that may be useful is printing the elements of collections or arrays. Most of the time, we use it for debugging purposes.

We can extend our utility class by adding some methods to simply joining the string representations of the elements. Plus, a custom separator and an optional limit parameter may be useful.

So, let’s define our join methods:

public static T> String join(T[] array, String separator)  return UtilsForCollections.join(array, separator, 0); > public static T> String join(T[] array, String separator, int limit)  if (limit > 0 && array.length > limit)  return Arrays.stream(array).limit(limit).map(String::valueOf) .collect(Collectors.joining(separator)) + separator + ". "; > return Arrays.stream(array).map(String::valueOf) .collect(Collectors.joining(separator)); > public static T> String join(CollectionT> collection, String separator)  return UtilsForCollections.join(collection, separator, 0); > public static T> String join(CollectionT> collection, String separator, int limit)  if (limit > 0 && collection.size() > limit)  return collection.stream().limit(limit).map(String::valueOf) .collect(Collectors.joining(separator)) + separator + ". "; > return collection.stream().map(String::valueOf) .collect(Collectors.joining(separator)); >

Then, let’s use our join method with a separator of comma and a limit parameter of 3:

String[] array = new String[]  "apple", "banana", "orange", "avocado", "mango" >; String joined = UtilsForCollections.join(array, ", ", 3); System.out.println(joined);

Last, we will see the output, maximum of 3 elements joined:

Finally

In this tutorial, we explained how to implement a simple utility class for collections by the help of Java 8 Stream API.

There are many possible methods to implement which are likely to come in handy when we are dealing with collections.

So, what do you think about any other useful methods to include in our utility class? Just feel free to comment below!

All the code samples given in this tutorial are available over on GitHub.

Источник

Java Collections Utility Class

The Collections utility class consists exclusively of static methods that operate on or return collections. It contains polymorphic algorithms that operate on collections, «wrappers», which return a new collection backed by a specified collection,

Some useful method in Collections class:

Method Signature Description
Collections.sort(List myList) Sort the myList (implementation of any List interface) provided an argument in natural ordering.
Collections.sort(List, comparator c) Sort the myList(implementation of any List interface) as per comparator c ordering (c class should implement comparator interface)
Collections.shuffle(List myList) Puts the elements of myList ((implementation of any List interface)in random order
Collections.reverse(List myList) Reverses the elements of myList ((implementation of any List interface)
Collections.binarySearch(List mlist, T key) Searches the mlist (implementation of any List interface) for the specified object using the binary search algorithm.
Collections.copy(List dest, List src) Copy the source List into dest List.
Collections.frequency(Collection c, Object o) Returns the number of elements in the specified collection class c (which implements Collection interface can be List, Set or Queue) equal to the specified object
Collections.synchronizedCollection(Collection c) Returns a synchronized (thread-safe) collection backed by the specified collection.

Let’s take the example of List sorting using Collection class. We can sort any Collection using “Collections” utility class. i.e.; ArrayList of Strings can be sorted alphabetically using this utility class. ArrayList class itself is not providing any methods to sort. We use Collections class static methods to do this. Below program shows use of reverse(), shuffle(), frequency() methods as well.

package utility; import java.util.Collections; import java.util.ArrayList; import java.util.List; public class CollectionsDemo < public static void main(String[] args) < ListstudentList = new ArrayList(); studentList.add("Neeraj"); studentList.add("Mahesh"); studentList.add("Armaan"); studentList.add("Preeti"); studentList.add("Sanjay"); studentList.add("Neeraj"); studentList.add("Zahir"); System.out.println("Original List " + studentList); Collections.sort(studentList); System.out.println("Sorted alphabetically List " + studentList); Collections.reverse(studentList); System.out.println("Reverse List " + studentList); Collections.shuffle(studentList); System.out.println("Shuffled List " + studentList); System.out.println("Checking occurance of Neeraj: " + Collections.frequency(studentList, "Neeraj")); > > 

java collection uitlity image1

Using Collections class we can copy one type of collection to another type. Collections provide us copy method to copy all the elements from source to destination. Below program demonstrates the use of copy function. Here size of source collection and destination collection should be same else we will get following exception.

java collection uitlity image2

import java.util.Collections; import java.util.*; public class CopyListDemo < public static void main(String[] args) < List myFirstList = new ArrayList(); List mySecondList = new ArrayList(); myFirstList.add(10); myFirstList.add(20); myFirstList.add(20); myFirstList.add(50); myFirstList.add(70); mySecondList.add(11); mySecondList.add(120); mySecondList.add(120); mySecondList.add(150); mySecondList.add(170); System.out.println("First List-"+ myFirstList); System.out.println("Second List-"+ mySecondList); Collections.copy(mySecondList, myFirstList ); System.out.println("Second List After Copy-"+ mySecondList); > > 

java collection uitlity image3

Java Code Editor:

Follow us on Facebook and Twitter for latest update.

Источник

Читайте также:  Python pip install pypiwin32
Оцените статью