Java 11 Developer Certification - Array Special Concepts

November 17, 2020

What we are covering in this lesson

  1. Unboxing in array
  2. List - Special Concepts
  3. Methods to create copy of an array

Unboxing in array

Arrays are fuzzy about their datatypes. We can rely on Java to autobox to and unbox from wrappers for us in many instances, this is not true for arrays. So the statements Long[] longArr = new int[2] or Integer[] intArr = new int[2] will throw compiler error for Incompatible Types. Also, the java.util.Arrays static methods that compare arrays, will not accept two arrays of different types even if they’re types that are normally widened or autoboxed on an individual level. So Arrays.equals(int[], Integer[]) or Arrays.compare(int[], Integer[]) will throw compiler error. This also applied for Arrays.mismatch.

package maxCode.online.Arrays;

import java.util.Arrays;

public class ArrayExtras {
	public static void main(String[] args) {
		int a = 0, b = 0;
		// You can assign an int variable to a long
		long myLong = a;
		System.out.println("myLong = " + myLong);

		// These are valid
		long[] longArray = { 0, 1, 2, 3, 4 };
		long[] myLongArray = new long[2];
		myLongArray[0] = a;
		myLongArray[1] = b;
		System.out.println("longArray = " + Arrays.toString(longArray));
		System.out.println("myLongArray = " + Arrays.toString(myLongArray));

		// And you know you can do this. Java autoboxes
		Integer aInteger = a;
		System.out.println("aInteger = " + aInteger);

		Integer[] integerArray = { 0, 1, 2, 3, 4 };
		System.out.println("integerArray = " + Arrays.toString(integerArray));

		Integer[] myIntegerArray = new Integer[2];
		// You can mix and match Integer, int here
		myIntegerArray[0] = aInteger;
		myIntegerArray[1] = b;
		System.out.println("myIntegerArray = " + Arrays.toString(myIntegerArray));
		
		System.out.println("\n---- Test methods with common super class");
		Number[] myNumberArray = { 0, 1, 2, 4, 5 };
		
		System.out.println("Arrays.mismatch(myNumberArray, integerArray) = "
		 		+ Arrays.mismatch(myNumberArray, integerArray));
		
		System.out.println("Arrays.equals(myNumberArray, integerArray) = " + Arrays.equals(myNumberArray, integerArray));

        // int compare = Arrays.compare(myNumberArray, integerArray);
	}
}

Output

myLong = 0
longArray = [0, 1, 2, 3, 4]
myLongArray = [0, 0]
aInteger = 0
integerArray = [0, 1, 2, 3, 4]
myIntegerArray = [0, 0]

---- Test methods with common super class
Arrays.mismatch(myNumberArray, integerArray) = 3
Arrays.equals(myNumberArray, integerArray) = false

The last part of the code compiles successfully since Integer extends Number. The commented code at the end will throw compiler error if uncommented, reason being when comparing different typed arrays, they need to implement the Comparable interface and be cast to a Comparable array and the compareTo method must compare a super class shared by both. So specifically, the area here is that java.lang.Number doesn’t implement Comparable.

List - Special Concepts

Most important thing to note here is that List.of and List.copyOf returns a immutable list objects. In the below code, firstList will create a mutable list of firstString array elements but secondList will create a list of list, and the difference is class names as seen in the output.

The method list.of can take an array of elements and create a list out of it or it can take a variable argument list of objects (a.k.a. varags). Since we didn’t pass an array to it in the code, it assumed a variable argument list of objects and created an array of one element the first and only element being the list we passed as the argument.

The method list.sublist got very similar features to the Arrays.asList method, such that the return list is backed by the original list. So non-structural changes to the return list are reflected in the original list. And this can be seen in the sublist output.

If in case we replace Arrays.asList(firstString).subList(0, 5) with firstString.subList(0, 5), then the code will throw UnsupportedOperationException, since we are trying to sort an immutable list and that is not permitted.

Then we have the toArray example, which returns the same reference and hence the equality returns true. It can also be called without having to assign it to another variable. One important thing to note here is that if we pass the length arrayLength as something less than the number of parameters in the list, then on using toArray, the values do not get populated. So if we pass 3 as arrayLength, the values in aArray and bArray will be null. If you always want an array that represents the elements exactly in the list, you can pass a 0 length array, as we have done in the below code for arrayRepresentation array. Also, we can call toArray without any parameter, it will return an array of object.

package maxCode.online.Arrays;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ArraysAndLists {
	public static void main(String[] args) {
		String[] firstString = { "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz" };

		List firstList = List.copyOf(Arrays.asList(firstString));
		List secondList = List.of(firstList);

		System.out.println("firstList = " + firstList.toString());
		System.out.println("secondList = " + secondList.toString());

		Object o = firstList.get(0);
		System.out.println(o.getClass().getName());
		o = secondList.get(0);
		System.out.println(o.getClass().getName());

		System.out.println("\n--------  subList example ---------");
		List subList = Arrays.asList(firstString).subList(0, 5);
		System.out.println("subList = " + subList.toString());

		// Sort the sublist
		subList.sort(Collections.reverseOrder());
		System.out.println("subList after reverse = " + subList.toString());
		System.out.println("firstString array  = " + Arrays.toString(firstString));
		System.out.println("firstList = " + firstList.toString());

		// Now let's look at toArray
		System.out.println("\n--------  toArray examples ---------");
		int arrayLength = firstList.size(); // arrayLength changes results

		// Set up a new array which we will pass to toArray
		String[] aArray = new String[arrayLength];

		// Calling toArray without assigning returned array to a variable
		firstList.toArray(aArray);
		System.out.println("aArray array  = " + Arrays.toString(aArray));

		// Set up another new array which we will pass to toArray
		String[] bArray = new String[arrayLength];

		// Calling toArray assigning returned array to a variable;
		String[] nextArray = (String[]) firstList.toArray(bArray);
		System.out.println("bArray array  = " + Arrays.toString(bArray));
		System.out.println("nextArray array  = " + Arrays.toString(nextArray));
		System.out.println("nextArray.equals(bArray) = " + nextArray.equals(bArray));

		System.out.println("\n------- Final toArray examples --------");
		// If you always want an array that represents the elements
		// exactly in the list, you can pass a 0 length array
		String[] arrayRepresentation = (String[]) firstList.toArray(new String[0]);
		System.out.println("arrayRepresentation array  = " + Arrays.toString(arrayRepresentation));

		// You can call toArray with no parameter, it returns an array of Object
		Object[] objectArray = firstList.toArray();
		System.out.println("objectArray array  = " + Arrays.toString(objectArray));

		String[] newRepresentation = (String[]) objectArray;
		System.out.println("newRepresentation array  = " + Arrays.toString(newRepresentation));
	}
}

Output

firstList = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz]
secondList = [[abc, def, ghi, jkl, mno, pqr, stu, vwx, yz]]
java.lang.String
java.util.ImmutableCollections$ListN

--------  subList example ---------
subList = [abc, def, ghi, jkl, mno]
subList after reverse = [mno, jkl, ghi, def, abc]
firstString array  = [mno, jkl, ghi, def, abc, pqr, stu, vwx, yz]
firstList = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz]

--------  toArray examples ---------
aArray array  = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz]
bArray array  = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz]
nextArray array  = [abc, def, ghi, jkl, mno, pqr, stu, vwx, yz]
nextArray.equals(bArray) = true

------- Final toArray examples --------
arrayRepresentation array  = [mno, jkl, ghi, def, abc, pqr, stu, vwx, yz]
objectArray array  = [mno, jkl, ghi, def, abc, pqr, stu, vwx, yz]
newRepresentation array  = [mno, jkl, ghi, def, abc, pqr, stu, vwx, yz]

Methods to create copy of an array

There are overall 5 methods which we will cover in this topic. Let see them one by one, assuming we have a String array like below

String[] stringArray = {"abc", "def", "ghi"}

clone method

  • inherited from Object class
  • Creates a new array reference but the elements are not cloned (shallow copy)
  • Array created is mutable

String[] clonedArray = stringArray.clone();

Arrays.copyOf method

  • static method in java.lang.Arrays
  • Creates a new array reference but the elements are not cloned (shallow copy)
  • Array created is mutable
  • Can be used to create array which is truncated from original
  • Can also be used to create array larger than original, additional elements get default values

    String[] copyOf1 = Arrays.copyOf(stringArray, stringArray.length);
    String[] copyOf2 = Arrays.copyOf(stringArray, 2);   //smaller array
    String[] copyOf3 = Arrays.copyOf(stringArray, 10);  //larger array

Arrays.copyOfRange method

  • static method in java.lang.Arrays
  • Creates a new array reference from the selected range but the elements are not cloned (shallow copy)
  • Array created is mutable

String[] copyRange1 = Arrays.copyOfRange(stringArray, 0, 1);

List.copyOf method

  • static method in List
  • Creates a new List using shallow copy
  • Makes immutable copy of list
  • Resulting array from toArray is not immutable
List<String> listCopy = List.copyOf(Arrays.asList(stringArray));    //immutable copy of list
String[] newArr = listCopy.toArray(new String[0]);  //mutable array

System.arraycopy

  • static method on System
  • Populates an array reference with a copy of the array passed to it
  • Creates mutable array
  • shallow copy
String[] systemClonedArray =  new String[stringArray.length];
System.arraycopy(stringArray, 0, systemClonedArray, 0, stringArray.length);