- Create a Utility Class in Java
- Usage of Utility Class in Java
- Writing a Utility Class for Collections in Java 8
- Utility Classes
- Static Classes in Java
- Array to Collection Conversion
- Power of Java 8 Stream API
- Handling Primitive Types
- Ordered Sets
- Collection to Collection Conversions
- Filtering Arrays and Collections
- Concatenate Elements into a String
- Finally
Create a Utility Class in Java
Utility classes in Java are also known as Helper Class. It is an efficient way to create methods that can be re-used. The code we need to use over and over again can be put inside a utility class.
Usage of Utility Class in Java
The Java utility class is a stateless class that cannot be instantiated and declared using final and public keywords. In the example given below, we have a UtilityClassExample , which has a private constructor that prevents instantiation. For example, there are many examples of Util classes in Java like Apache StringUtils , CollectionUtils , or java.lang.Math .
The methods in the utility class should be declared static and not abstract as object methods need instantiation. The final keyword prevents subclassing. Here, we create our own Utility class with a private constructor, which, when invoked, throws an exception. Since we declared a private constructor, default can not be created; hence class can not be instantiated.
In the code given below, we have all members of the UtilityClassExample static. If we need to add or subtract two int or float type variables, we created methods in the utility class to re-use the code. We also have a method that returns a number multiplied by ten.
In the method addFloatValues() , we have also used Math.round() to round off the result to the nearest int. The Float class has the sum() method that returns the sum of two float arguments. We call each member method of this utility class passing arguments and print the output in the main() method of the class TestUtitity . Thus this utility class has methods that are used very often.
public final class UtilityClassExample private static final int constantValue = 10; private UtilityClassExample() throw new java.lang.UnsupportedOperationException("Utility class and cannot be instantiated"); > public static int addIntValues(int i,int j) int sum = i + j; return sum; > public static int subIntValues(int i,int j) int diff = 0; if(i>j) diff = i - j; >else diff = j - i; > return diff; > public static float addFloatValues(float i, float j) float sum = Float.sum(i,j); return Math.round(sum); > public static float subFloatValues(float i, float j) float diff = 0.00f; if(i>j) diff = i - j; >else diff = j - i; > return diff; > public static int returnValAfterMultiplying(int i) return i * constantValue; > > class TestUtility public static void main(String [] args) int a = 4; int b = 9; int c = 7; float d = 3.12f; float e = 6.85f; System.out.println(+a+" multiplied by ten is : "+UtilityClassExample.returnValAfterMultiplying(a)); System.out.println(b+"+"+c+" is : "+UtilityClassExample.addIntValues(b,c)); System.out.println(d+"+"+e+" is : "+UtilityClassExample.addFloatValues(d,e)); System.out.println(b+"-"+a+" is : "+UtilityClassExample.subIntValues(b,a)); System.out.println(e+"-"+d+" is : "+UtilityClassExample.subFloatValues(e,d)); > >
4 multiplied by ten is : 40 9+7 is : 16 3.12+6.85 is : 10.0 9-4 is : 5 6.85-3.12 is : 3.73
It is not recommended to use a Utility class of your own as it reduces flexibility.
Rupam Saini is an android developer, who also works sometimes as a web developer., He likes to read books and write about various things.
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.