Java util classes static

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.

Источник

Что значит static в Java?

В Java ключевые слова – это зарезервированные слова, которые нельзя использовать в качестве идентификаторов. Всего в Java 57 ключевых слов. Одним из них является «static».

Введение

В Java статическое ключевое слово в основном используется для управления памятью. Может использоваться с переменными, методами, блоками и вложенными классами. Это ключевое слово, которое используется для совместного использования одной и той же переменной или метода данного класса. В основном, static используется для постоянной переменной или метода, который одинаков для каждого экземпляра класса. Основной метод класса обычно помечается как статический.

Чтобы создать статический член (блок, переменную, метод, вложенный класс), вам необходимо предшествовать его объявлению с ключевым словом static. Когда член класса объявлен как статический, к нему можно получить доступ до того, как будут созданы объекты его класса, и без какой-либо ссылки на объект.

В языке программирования Java ключевое слово static является модификатором отсутствия доступа и может использоваться для следующих целей:

Статический блок

Если вам нужно выполнить вычисления для инициализации статических переменных, вы можете объявить статический блок, который выполняется ровно один раз, когда класс загружается впервые. Как использовать статический блок:

// Java program to demonstrate the use of static blocks import java.util.*; public class BlockExample < // static variable static int j = 10; static int n; // static block static < System.out.println("Static block initialized."); n = j * 8; >public static void main(String[] args) < System.out.println("Inside main method"); System.out.println("Value of j : "+j); System.out.println("Value of n : "+n); >>

Когда вы выполняете вышеуказанную программу, статический блок инициализируется и отображает значения инициализированных переменных.

Static block initialized Inside main method Value of j:10 Value of n : 80

Статическая переменная

Когда вы объявляете переменную как статическую, создается единственная копия переменной, которая распределяется между всеми объектами на уровне класса. Это, по сути, глобальные переменные, все экземпляры класса имеют одну и ту же статическую переменную. Могут быть созданы только на уровне класса.

Теперь давайте разберемся с этим на примере.

// Java program demonstrate execution of static blocks and variables import java.util.*; public class VariableExample < // static variable static int j = n(); // static block static < System.out.println("Inside the static block"); >// static method static int n() < System.out.println("from n "); return 20; >// static method(main !!) public static void main(String[] args) < System.out.println("Value of j : "+j); System.out.println("Inside main method"); >>

Когда вы выполняете вышеуказанную программу, она выполняет статический блок и переменную в порядке, как определено в вышеуказанной программе.

from n Inside the static block Value of j: 20 Inside main method

Статические методы

Когда метод объявляется с ключевым словом static, он называется статическим методом. Наиболее распространенным примером является метод main(). Методы, объявленные как статические, могут иметь следующие ограничения:

  • Они могут напрямую вызывать только другие статические методы.
  • Они могут получить доступ к данным напрямую.

Теперь давайте разберемся на примере:

// java program to demonstrate restriction on static methods public class StaticMethodExample < // static variable static int j = 100; // instance variable int n = 200; // static method static void a() < a = 200; System.out.println("Print from a"); // Cannot make a static reference to the non-static field b n = 100; // compilation error // Cannot make a static reference to the // non-static method a2() from the type Test a2(); // compilation error // Cannot use super in a static context System.out.println(super.j); // compiler error >// instance method void a2() < System.out.println("Inside a2"); >public static void main(String[] args) < // main method >>

В приведенных выше примерах вы можете видеть, как налагаются ограничения на статические методы, а также как вам разрешается использовать ключевое слово super в статическом контексте.

Статический класс

Класс можно сделать статическим, только если он является вложенным классом. Вложенный статический класс не нуждается в ссылке на Outer. В этом случае статический класс не может получить доступ к нестатическим членам класса Outer. Давайте рассмотрим пример, чтобы понять, как это работает

public class NestedExample < private static String str= "Edureka" //Static class static class MyNestedClass< //non-static method public void disp()< System.out.println(str); >> public static void main(String args[])

Когда вы выполняете приведенный выше код, ваш вывод выглядит так:

Источник

Читайте также:  Return php как работает
Оцените статью