Level 1
Creating a Generic Immutable List
Create an immutable class ImmutableList that operates as a list. The list should be ordered, i.e., the position of the items in the list matters. Your immutable list should not implement the List interface but should contain a List instead.
import java.util.List;class ImmutableList<T> { private final List<T> list;}
Your class should have two constructors, both accept items to populate your new immutable list. The first one takes in a generic List containing the items as an argument; the second takes in a sequence of items as variable-length arguments (or varargs). Variable-length arguments allow you to pass an unspecified number of arguments to a method or constructor. You can read up about varargs if you are unfamiliar with this Java feature.Using varargs with generic type parameters could be unsafe. Varargs is a syntactic sugar for an array, which is covariant in Java and potentially unsafe as you have seen in class (recall assigning a Shape array variable to reference a Circle array, and then storing a Rectangle as one of the array elements).To tell the compiler that you know what you are doing is type-safe, when you declare a method that takes in varargs with a generic type parameter, add an annotation @SafeVarargs before the method.Your class should also have an appropriate toString method which prints out the contents of the List.
jshell> /open ImmutableList.javajshell> new ImmutableList<Integer>(1,2,3)$.. ==> [1, 2, 3]jshell> new ImmutableList<Integer>(Arrays.asList(1,2,3))$.. ==> [1, 2, 3]jshell> new ImmutableList<Integer>(new ArrayList<Integer>(Arrays.asList(1,2,3)))$.. ==> [1, 2, 3]jshell> new ImmutableList<Integer>()$.. ==> []jshell> /exit
|
Check the format correctness of the output by running the following on the command line:
$ javac -Xlint:rawtypes *.java$ jshell -q < test1.jsh
The -Xlint:rawtypes flag would warn you if you forget to specify generics and use raw types instead.Check your styling by issuing the following
$ checkstyle *.java
|
Level 2
Manipulating the List
Include the method add (append an item to the list), replace (replace all occurences of an item with another), and remove (remove the first occurence of an item) methods. Remember your list has to be immutable.
jshell> /open ImmutableList.javajshell> List<Integer> mList = new ArrayList<Integer>(Arrays.asList(1,2,3))jshell> ImmutableList<Integer> imList = new ImmutableList<Integer>(mList)jshell> imList.remove(3)$.. ==> [1, 2]jshell> imListimList ==> [1, 2, 3]jshell> imList.remove(3).add(2)$.. ==> [1, 2, 2]jshell> imListimList ==> [1, 2, 3]jshell> imList.remove(6)$.. ==> [1, 2, 3]jshell> imList.add(1).replace(1,3)$.. ==> [3, 2, 3, 3]jshell> imList.add(1).replace(1,1)$.. ==> [1, 2, 3, 1]jshell> imList.replace(6,3)$.. ==> [1, 2, 3]jshell> mList.set(0,10)$.. ==> 1jshell> mListmList ==> [10, 2, 3]jshell> imListimList ==> [1, 2, 3]jshell> Integer[] array = {1, 2, 3}jshell> ImmutableList<Integer> imList = new ImmutableList<Integer>(array)jshell> array[0] = 10$.. ==> 10jshell> imListimList ==> [1, 2, 3]jshell> new ImmutableList<Integer>(List.of(4,5,6)).add(7)$.. ==> [4, 5, 6, 7]jshell> ImmutableList<String> stringList = new ImmutableList<String>(Arrays.asList("One","Two","Three"))jshell> stringList.add("Four");$.. ==> [One, Two, Three, Four]jshell> stringListstringList ==> [One, Two, Three]jshell> /exit
Check the format correctness of the output by running the following on the command line:
$ javac -Xlint:rawtypes *.java$ jshell -q < test2.jsh
Check your styling by issuing the following
$ checkstyle *.java
|
Level 3
Limiting the List
Lets create a new method limit in the ImmutableList class. The limit method takes in a long value and then returns an ImmutableList truncated to the length specified by that long value.Consider the case where you pass in a negative number. In this case, lets throw an IllegalArgumentException with the exception message limit size < 0 .It is important to note that, the test cases below catch unchecked exceptions for the purpose of testing only. It is an unusual coding practice to catch unchecked exceptions, as unchecked exceptions are usually caused by bugs or improper use of APIs, and the application usually cannot recover from such exceptions.
jshell> /open ImmutableList.javajshell> new ImmutableList<Integer>(1,2,3).limit(1)$.. ==> [1]jshell> new ImmutableList<Integer>(1,2,3).limit(10)$.. ==> [1, 2, 3]jshell> ImmutableList<Integer> list = new ImmutableList<Integer>(1,2,3)jshell> list.limit(0)$.. ==> []jshell> listlist ==> [1, 2, 3]jshell> list = list.limit(0)jshell> try { ...> new ImmutableList<Integer>(1,2,3).limit(-1); ...> } catch (IllegalArgumentException e) { ...> System.out.println(e); ...> }java.lang.IllegalArgumentException: limit size < 0jshell> /exit
|
Check the format correctness of the output by running the following on the command line:
$ javac -Xlint:rawtypes *.java$ jshell -q < test3.jsh
Check your styling by issuing the following
$ checkstyle *.java
|
Level 4
List Equality and Sorting the List
Write an overridden method equals that takes in another ImmutableList and checks for equality. Two immutable lists are the same if they contain the same elements (as determined by each elements equals method).We would also like to sort the list using an arbitrary Comparator . Lets create a sorted method that takes in a Comparator and returns the ImmutableList as sorted by this Comparator . What if a null value is passed as a Comparator ? To preempt such irresponsible actions, lets throw a NullPointerException with the exception message Comparator is null .
jshell> /open ImmutableList.javajshell> jshell> ImmutableList<Integer> list = new ImmutableList<Integer>(1,2,3)jshell> list.equals(list)$.. ==> truejshell> list.equals(Arrays.asList(1,2,3))$.. ==> falsejshell> list.equals(new ImmutableList<Integer>(1,2,3))$.. ==> truejshell> list.equals(new ImmutableList<Integer>(1,2))$.. ==> falsejshell> list.equals(new ImmutableList<Integer>(1,2,3,3))$.. ==> falsejshell> list.equals(new ImmutableList<Integer>(3,2,1))$.. ==> falsejshell> list.sorted(new Comparator<Integer>() { ...> public int compare(Integer i1, Integer i2) { ...> return i2 - i1; ...> }})$.. ==> [3, 2, 1]jshell> listlist ==> [1, 2, 3]jshell> try { ...> new ImmutableList<Integer>(1,2,3).sorted(null); ...> } catch (NullPointerException e) { ...> System.out.println(e); ...> }java.lang.NullPointerException: Comparator is nulljshell> /exit
|
Check the format correctness of the output by running the following on the command line:
$ javac -Xlint:rawtypes *.java$ jshell -q < test4.jsh
Check your styling by issuing the following
$ checkstyle *.java
|
Level 5
Implement a toArray Method
Create overloaded methods toArray that takes in either no argument, or an array as an argument. The toArray method without argument will return the items in the list as an array of type Object[] . The toArray method with an array as an argument is a generic method that will return the items in the list in an array of the same type as the argument. The behavior of toArray of your list is similar to that of toArray of List , with the only difference being the error message associated with the exception thrown.When an array of the wrong type is being passed into the ImmutableList, an ArrayStoreException exception is thrown with the exception message Cannot add element to array as it is the wrong type .As for passing a null argument? Once again, we throw a NullPointerException with the exception message Input array cannot be null .
jshell> /open ImmutableList.javajshell> new ImmutableList<Integer>(1,2,3).toArray()$.. ==> Object[3] { 1, 2, 3 }jshell> new ImmutableList<Integer>().toArray()$.. ==> Object[0] { }jshell> Integer[] integers = new ImmutableList<Integer>(1,2,3).toArray(new Integer[0])jshell> integersintegers ==> Integer[3] { 1, 2, 3 }jshell> try { ...> new ImmutableList<Integer>(1,2,3).toArray(new String[0]); ...> } catch (ArrayStoreException e) { ...> System.out.println(e); ...> }java.lang.ArrayStoreException: Cannot add element to array as it is the wrong typejshell> try { ...> new ImmutableList<Integer>(1,2,3).toArray(null); ...> } catch (NullPointerException e) { ...> System.out.println(e); ...> }java.lang.NullPointerException: Input array cannot be nulljshell> /exit
|
Check the format correctness of the output by running the following on the command line:
$ javac -Xlint:rawtypes *.java$ jshell -q < test5.jsh
Check your styling by issuing the following
$ checkstyle *.java
|
Bonus Level
Implement Map and Filter Methods
Now, lets create two new methods in the ImmutableList class.First, the filter method. The filter method will return an ImmutableList with elements based on a Predicate you pass to it. Remember that Predicate is a generic functional interface, and therefore it has one method to implement: test .Next, implement the map method. The map method will return an ImmutableList in which all elements are transformed based on a Function you pass to it. Again, Function is a generic functional interface, and therefore it has one method to implement: apply . Remember that the input type may not be the same as the output type: consider a mapping from String to Integer using the length() method.Try passing your own Predicate s and Function s to these methods! We use lambda expressions in the following test cases below. You are encouraged to read more about lambda expressions as you will be using them extensively for the rest of the semester.
jshell> /open ImmutableList.javajshell> new ImmutableList<Integer>(1,2,3).filter(x -> x % 2 == 0)$.. ==> [2]jshell> new ImmutableList<String>("one", "two", "three").filter(x -> x.hashCode()%10 > 5)$.. ==> [two, three]jshell> Predicate<Object> p = x -> x.hashCode()%10 == 0jshell> new ImmutableList<String>("one", "two", "three").filter(p)$.. ==> []jshell> ImmutableList<Integer> list = new ImmutableList<String>("one", "two", "three").map(x -> x.length())jshell> /var list| ImmutableList<Integer> list = [3, 3, 5]jshell> Function<Object,Integer> f = x -> x.hashCode()jshell> ImmutableList<Number> list = new ImmutableList<String>("one", "two", "three").map(f)jshell> /var list| ImmutableList<Number> list = [110182, 115276, 110339486]jshell> new ImmutableList<Integer>(1,2,3).filter(x -> x > 3).map(x -> x + 1)$.. ==> []jshell> new ImmutableList<Integer>(1,2,3).filter(x -> x > 2).map(x -> x + 1)$.. ==> [4]jshell> new ImmutableList<Integer>(1,2,3).map(x -> x + 1).filter(x -> x > 2)$.. ==> [3, 4]jshell> new ImmutableList<String>().filter(s -> s.endsWith("s"))$.. ==> []jshell> new ImmutableList<String>().map(s -> s.endsWith("s"))$.. ==> []jshell> /exit
|
|
Reviews
There are no reviews yet.