Skip to content

Java arrays vs. Vavr vavr.collection.Array

Hello! This post opens a series dedicated to comparing data structures implementations in “vanila” Java and Vavr library. We will start from reviewing an array – one of the most common data structure in software development. Array assumes that its length is fixed and any given element can be accessed using its numeric index that belongs to a range [0; array length – 1].

Throughout this article we will review definition of arrays in computer science and then move to concrete implementations in Java and Vavr. There are following points for each of them: initialization (declaration), accessing an element, adding an additional element, replacing an element, sorting, filtering and comparing.

Table of Contents

Array as a data structure

Before we will cover concrete implemenetations in vanila Java and Vavr, we need to review what is an array itself. In computer programming, array is a data structure that stores a sequence of values that are all of the same type. A typical array is presented on the graph below:

Graph 1. Array data structure representation

Array uses index of each element in order to access it quickly. The important note here is that arrays have zero-based indexing, which means that first element of array has index of 0. Some researchers also refer to the first element’s index as a foundational or base index. So, we can say that array with length of n has elements from 0 to n-1.

Another important characteristic of arrays is their fixed length. Once we create an array, we can’t enlarge it or reduce it. Java supplies out-of-the-box an array implementation, that is very commonly used. Another approach is to use array from Vavr library.

Arrays in vanila Java

In this section we will go through array implementation from vanila Java. Array here is defined as a container object that holds a fixed number of values of a single type. Arrays consist of elements, each of which can be called by its index (index is an integer value starting from 0).

Declare array

To declare array we need to specify its type and name. Arrays in Java can hold both primitives (like int, char or double) as well objects (like String or Object). Take a look on the code snippet below:

int[] numbers = new int[10];

char[] letters = {'a', 'b', 'c', 'd', 'e', 'f'};

String cities[] = {"Saint-Petersburg", "Madrid", "Buenos Aires", "Jihlava"};

As you can note, we can use two ways to initialize a new array:

  1. Using new operator and specify length of array
  2. Create array and initialize wuth literal values in a time of declaration

In both cases Java reserves the specific space in memory for array. This is called a memory allocation. NB that there are two ways to position [] array brackets: after type or after name. Both are legal (some tech interviewers may ask you this question, thinking that brackets should appear only after type; run away from such “tech talents”), although Java discourages you to use after-name brackets.

Is array an object?

When we talk about array lists we surely know that they are objects. Also, when you ask a question from the title of this subsection, many Java developers are confused. This is understandable, because for some languages it is true that their arrays are not objects. However, Java arrays are objects, yet a bit special type from a first glance. You can easily prove it by running following code:

int[] numbers = {1,2,3,4,5};

if (numbers instanceof Object){
	System.out.println("Array in Java is an object");
}

Java SE specification states in the chapter 10 that arrays are objects. In other words, array has all methods inherited from java.lang.Object; also arrays implement Cloneable and Serializable interfaces too.

Access an element in array

As it was stated in previous sections, array utilizes a numeric indexing to acccess elements from 0 to n-1, where n is a size of array. To retrieve an element of array in Java you need to specify its index:

String[] names = "Anna", "Barbora", "Carolina", "Denisa";

String name = names[2];

System.out.println(name); // Carolina

If you access an index that is higher than length-1 or lower than 0, Java will throw an java.lang.ArrayIndexOutOfBoundsException.

Add new element to array

We already talked that Java array has a fixed size. So, in order to append a new element we can do following steps:

  1. Get a length of old array
  2. Copy all elements from the old array using Arrays utility class to new array with length oldLength+1
  3. Insert new element at the last position

Take a look on the code snippet below:

String[] names = "Anna", "Barbora", "Carolina", "Denisa";

String name = "Eliska";

// we need to add Eliska to array

// step 1. Get old array length

int oldLength = names.length;

// step 2. Copy old elements

int[] newNames = Arrays.copyOf(names, oldLength+1);

// step 3. Add Eliska

newNames[4] = name;

Replace an element in array

While we can’t add a new element to array (without a magic, that we discussed previously), we can replace or re-assign an element in array to a new value:

String[] cities = {"Madrid", "Buenos Aires", "Ciudad de Mexico", "Bogota", "Lima"};

cities[0] = "Barcelona";
String city = cities[0];
System.out.println(city); // = Barcelona

So, we changed a value in index 0 from Madrid to Barcelona string value (while, in a real life, I’ll prefer to stick to Madrid, not Barcelona 😉 ).

Get length of array

When we talk about collections in Java we remind a method size() that returns an integer value with a number of elements in a collection. Arrays offer a different way – we call length:

int[] numbers = {1,3,5,7,9,11};

int size = numbers.length;

From a technical point of view, length is not a method like the aforesaid size() method. This is a constant value that represents a number of elements (that is >=0). Java SE specification in section 10.7 points out that length field is public and final field of array object.

Filter an array

There is no out-of-the-box method to filter array in Java, however we can use a trick in order to achieve it. We can get a stream using Arrays.stream method and then apply stream filtering. Take a look on the code snippet below:

String[] names = {"Aneta", "Barbora", "Agata", "Denisa", "Anna"};

Arrays.stream(names).filter(name->name.startsWith("A")).forEach(System.out::println);

NB that Arrays.stream method is available since Java 8+.

Sort an array

In order to sort arrays in Java, we need to utilize Arrays utility class. There are two ways to sort an array using Arrays.sort()

  1. In ascending order (default approach)
  2. Specify Comparator to sort in specified order

Under the hood, Java uses a quicksort algorithm to sort arrays. Let have an example:

// in ascending order (default)

int[] numbers = {15, 98, 1, 9, 14, 32};

System.out.println(numbers);

Arrays.sort(numbers);

System.out.println(numbers);

// sort with comparator

Integer[] numbers2 = numbers = {15, 98, 1, 9, 14, 32};

System.out.println(numbers2);

Arrays.sort(numbers2, Collections.reverseOrder());

System.out.println(numbers2);

NB that comparator version works only with objects, not primitives. An another approach to sort is to convert an array to a list with Arrays.asList and then sort using stream operations.

Compare two arrays

Finally, let review how we can compare two arrays. Two arrays are equal if they contain the same elements in the same order. Also, two array references are considered equal if both are null. We can check equality using Arrays.equals method:

int[] numbers = {15, 98, 1, 9, 14, 32};
int[] numbers2 = {15, 98, 1, 9, 14, 32};

boolean areEquals = Arrays.equals(numbers, numbers2);

That is all about vanila Java arrays. Another array implementation is Vavr Array class. In the next section we will explore it and its difference with native Java one.

Arrays in Vavr

Vavr library has a class io.vavr.collection.Array that is defined as a wrapper for Object[] containing elements of type T. The graph below represents a position of Vavr Array among other Vavr Collections:

Graph 2. Place of arrays in the Vavr Collections hierarchy

Arrays as you could observe implement Vavr interfaces Seq and Traversable and inherit their methods as well.

NB that Vavr data structures are immutable, so all array manipulations return a new array, while the old one is not modified

Create Vavr arrays

Unlike to native Java arrays, Vavr ones are created in a different way. We can create them from given elements using of static method, generate from range or create from Vavr Streams. Have a look on the code snippet below:

Array<Integer> numbers1 = Array.ofAll(1, 2, 3, 4, 5, 6);

Array<Integer> numbers2 = Array.range(1,7);

NB there are two methods both accepts several elements: of and ofAll. The difference is that the first one accepts objects and create an array with a type of objects. Second accepts primitives and create an array with a wrapper type.

Add elements to array

Unlike Java, Vavr provides methods to modify an array and add new values. There are several ways to do so:

  • append (T t)
  • insert (T t, int position)

Let examine both of them deeper. Here is a code that demonstrates how to add elements to the Vavr array:

Array<String> names = Array.of("Anna", "Barbora", "Carolina", "Denisa", "Eva");

Array<String> result = names.append("Hana");

System.out.println(names);
System.out.println(result);

Access an element

Same as Java, Vavr array’s element is accessed by its numeric index, starting from 0 to array length – 1. But a syntax is same as in Java collections using method get(int index):

Array<String> names = Array.of("Anna", "Barbora", "Carolina", "Denisa", "Eva");

String name = names.get(2);

System.out.println(name); //Carolina

Filter an array

Vavr provides developers a convinient way to filter array without any hassle. As Traversable subclass, array has filter(Predicate p) method that returns a new array that satisfies given condition. Compare this code snippet with its vanila Java counterpart:

Array<String> names = Array.of("Aneta", "Barbora", "Agata", "Denisa", "Anna");
Array<String> results = names.filter(name->name.startsWith("A"));

Get length of an array

From Traversable array inherits length() method that returns an integer value equals number of elements in it.

Array<String> names = Array.of("Aneta", "Barbora", "Agata", "Denisa", "Anna");
int size = names.length(); //5

Sort an array

With sorted method you can sort elements of array. Vavr offers two overloaded versions:

  • Without arguments sorted(): sorts this elements according to their natural orde
  • With Comparator argument sorted(Comparator c): sorts elements based on a provided comparator

NB that elements of array have to implement Comparable marker interface, otherwise ClassCastException may be thrown. Here is an example code:

Array<Integer> numbers = Array.ofAll(16, 22, 4, 5, 19, 7, 80);
Array<Integer> sorted = numbers.sorted();

Replace an element in array

A logic of replacement is different in Vavr, comparing to vanila Java. While Java can replace a given element based on its index, Vavr accepts a concrete element to replace and replaces its first occurrence (replace) or all elements that equals to a given argument (replaceAll). Let me demonstrate it:

Array<String> cities = Array.of("Madrid", "Buenos Aires", "Prague", "Bogota", "Prague", "Cordoba");

// replace 1st occurence of Prague:

Array<String> result1 = cities.replace("Prague", "Lima");

// replace all Prague occurence to Lima

Array<String> result2 = cities.replaceAll("Prague", "Lima");

Compare two arrays

Like in vanila Java, Vavr uses equals method to compare arrays. In Vavr, Traversables override Object.equals with following conditions:

  1. Both objects are of same type
  2. Both contain same elements
  3. Both have same order of elements

Observe two code snippets below:

Array<String> cities1 = Array.of("Madrid", "Buenos Aires", "Prague", "Bogota", "Prague", "Cordoba");
Array<String> cities2 = Array.of("Madrid", "Buenos Aires", "Prague", "Bogota", "Prague", "Cordoba");

boolean result = cities1.equals(cities2); // true

In the first code snippet the result of comparing arrays is true as they both have same elements in the same order. In the second example, while arrays contain same elements, their order is not same:

Array<String> cities1 = Array.of("Cordoba", "Buenos Aires", "Bogota", "Prague", "Prague", "Madrid");
Array<String> cities2 = Array.of("Madrid", "Buenos Aires", "Prague", "Bogota", "Prague", "Cordoba");

boolean result = cities1.equals(cities2); // false

Conclusion

In this post we observed two common implementations of an array data structure in Java: one from “vanila” implementation of Java SE and one from Vavr library. We explored how to declare an array, add additional elements, filter, replace an element, sort and compare.

Both of implementations offer different approaches for same points and it is always good to consider which of them suites better the concrete use case.

References

  • Chapter 10, Java Language Specification read here
  • Sedgewick Robert and Wayne Kevin. Introduction to Programming in Java: An Interdisciplinary Approach 2nd edn. Addison-Wesley Professional. 2017
Copy link
Powered by Social Snap