0% found this document useful (0 votes)
33 views

Lecture4 - ArrayList

The ArrayList class provides a dynamic array that can grow and shrink as needed. It has useful methods like add, remove, get, and size. An ArrayList stores object references, not the objects themselves. A for-each loop simplifies iteration over collections without indexes. Lambda expressions and streams in Java 8 provide functional-style processing of collections.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
33 views

Lecture4 - ArrayList

The ArrayList class provides a dynamic array that can grow and shrink as needed. It has useful methods like add, remove, get, and size. An ArrayList stores object references, not the objects themselves. A for-each loop simplifies iteration over collections without indexes. Lambda expressions and streams in Java 8 provide functional-style processing of collections.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

CSC8313

OBJECT ORIENTED PROGRAMMING

The ArrayList collection – Lecture 4

1 1
LECTURE 4 OBJECTIVES
Understand the benefits of using the ArrayList
class and some of its common methods.

Appreciate the use of the for-each loop, auto-


boxing and wrapper classes.

Take a first look at the forEach method and


Stream API.

2 2
ARRAYS CAN BE USED AS FIELDS WITHIN CLASSES TO
MAKE OTHER DATA STRUCTURES

Stack<T>
A stack of some
- stackArray : T[] type, T
The data
store
- top : int
Index of last
+ push(T) element

+ pop()
Typical stack
methods + top() : T
+ isEmpty() : boolean

3
THE ARRAYLIST CLASS
An array's size is fixed upon creation – we do not always
know how many items we wish to store in a collection.

The ArrayList class provides a more powerful data structure


within the Collections framework.

It can grow and shrink dynamically as needed.

It also provides a useful set of methods through its public


interface for common tasks such as inserting or removing
elements.

4
JAVA.UTIL.ARRAYLIST<T>
The Java SDK provides a class ArrayList, placed within the
java.util package that:
 encapsulates an array of objects.

 provides methods for maintaining a general purpose list.

The type <T> of object stored in the internal array can be


instantiated during the creation of the ArrayList.

This is known as a Generic Type parameter, meaning the


ArrayList may store elements of any reference type.

5
EXAMPLE OF A SIMPLE GENERIC CLASS
public class Pair<T, S> {
private T first;
private S second;

public Pair(T f, S s) {
first = f; second = s;
}

public T getFirst() {
return first;
} //…etc

6
USING THE GENERIC CLASS
//using class with different types…
Pair<String, Integer> fruit = new
Pair<String, Integer>("Apple", 1);
String x = fruit.getFirst();

Pair<Die, Die> pod = new


Pair<Die, Die>(new Die(), new Die());
pod.getSecond().roll();
//…etc

7
INSTANTIATING AN ARRAYLIST
Examples of instantiating an ArrayList with different type
parameters:
 ArrayList<String> words = new ArrayList<String>();

 ArrayList<Name> friends = new ArrayList<Name>();

 ArrayList<Integer> marks = new ArrayList<Integer>();

But NOT ArrayList<int> - <T> must be a reference


type to be compatible with generics.

8
JAVA 7 DIAMOND SYNTAX
Java 7 has introduced a convenient syntax enhancement
for declaring array lists and other generic classes.

You need not repeat the type parameter in the constructor.


 ArrayList<String> names = new ArrayList<String>();

 ArrayList<String> names = new ArrayList<>();

The shortcut is called 'diamond operator' as the empty


brackets <> look like a diamond shape.

9
WRAPPERS AND AUTO-BOXING
Java has a wrapper class for each of the primitive types,
e.g. Integer for int, Double for double, etc.

Suppose we have an ArrayList of type Integer:


 ArrayList<Integer> marks = new ArrayList<>();

Both of these operations are syntactically valid:


 marks.add(5); //box
 int m = marks.get(0); //unbox

A procedure called autoboxing and unboxing ensures the


automatic conversion of a wrapper class type to its
corresponding primitive type and vice versa. 10
ARRAYLIST METHODS (SEE API FOR MORE)
Can add elements to the list: add(x), add(i,x)

Can remove elements from list: remove(x), remove(i)

Can retrieve an element at index ‘i’ using: get(i)

Can replace an element, x, at index ‘i’ using: set(i, x)

Can check if the list is empty: isEmpty()

Can check the number of objects currently stored: size()

Can clear all elements within the list: clear()

11
ARRAYLIST: SIZE V CAPACITY
When an ArrayList is first created it receives an initial
capacity of 10 elements.

The underlying array automatically re-sizes at runtime if


the original capacity has been reached.

Therefore the size of the ArrayList represents the


number of objects currently stored.

The capacity represents the number of objects that can


be stored until it needs to expand, i.e. The JVM will
reallocate more memory and copy elements over.

12
USING THE LIST INTERFACE TYPE
An ArrayList object can be stored in a variable container of
type List – this is a common interface for all list types in the
Java collections framework:
List<String> list = new ArrayList<>();
ArrayList<String> list = new ArrayList<>();

The former restricts you to use only methods defined in the


interface, but allows the data structure to be changed.

An ArrayList can be changed to any other class that


implements the List interface, e.g. LinkedList, Vector,
etc.

13
LIST INTERFACE’S IMPLEMENTING CLASSES
View the API at:
https://docs.oracle.com/javase/8/docs/api/java/util/List.html

List<String> list = new ArrayList<>();

List<String> list = new LinkedList<>();

List<String> list = new Vector<>();

14
ARRAYLIST: A COLLECTION OF REFERENCES
When we instantiate an ArrayList of different types, how
much memory is allocated? e.g.
 List<String> s = new ArrayList<>();

 List<Integer> i = new ArrayList<>();

 List<BigObject> o = new ArrayList<>();

The same memory would be allocated for each ArrayList,


that is enough memory to store 10 object references.
BigObject objects may require a huge amount of memory,
but the ArrayList will only store references, not the actual
objects themselves.

15
USING A FOR-EACH LOOP
Like a for-i loop but has a simplified syntax. It can be used
with an array or a collection class (e.g. ArrayList).

The loop does not require a counter; it will traverse through


each element within the collection, providing direct access
without needing to worry about index.

Syntax is:

for(elementType variable : collection) {


statements;
}
16
FOR-EACH: USE AND LIMITATIONS
for(int x : myArray) {
System.out.println(x);
}
It is only possible to access values stored within each
element when using a for-each loop, so you cannot modify
them, as with a for-i loop, e.g. a[i] = -99. 

As you have no access to the index, it is not possible to


know where the array value is within the collection.

You cannot process a subset of elements, e.g. all odd.


17
ARRAYLIST OF OBJECTS: EXAMPLE
Example of an ArrayList of 3 String objects, that are
traversed using the for-each loop and output in upper
case:
List<String> fruit = new ArrayList<>();
fruit.add("apple");
fruit.add("pear");
fruit.add("grape");

for (String s : fruit) {


System.out.println(s.toUpperCase());
}

18
ARRAYLIST OF OBJECTS: EXAMPLE (2)
Using a for-each loop you cannot update the object
reference stored in an ArrayList, but you can modify the
internal data of an object, e.g. Setting quantity:

List<Order> orders = new ArrayList<>();


orders.add(new Order("Beans", 55, 7));
orders.add(new Order("Milk", 99, 20));
//etc

for (Order o : orders) {


o.setQuantity(30);
totalcost += o.getCost();
}

19
THE JAVA 8 FOREACH METHOD
The addition of functional programming constructs in the
8th release of Java has provided another way of
processing collections – the forEach method.

The syntax is.


 collection.forEach(lambda expression);

 orderList.forEach(od -> od.toString()); //an example

Aggregate operations, such as forEach, process elements


from a stream and cleanly separate the logic of iteration
and element execution, allowing parallelism.
20
WHAT IS A LAMBDA EXPRESSION ?
Traditionally, a method would accept arguments, representing
either primitive or reference type data.

With lambdas we can treat functionality as a method argument, or


code as data, i.e. pass in a method.

For one line method bodies, you can omit both the braces {} and
the return keyword. Parameter types can often be inferred from
the context of the surrounding code.
 orderList.forEach((Order od) -> { od.getCost(); });

 orderList.forEach( od -> od.getCost()); //type Order inferred

21
STREAMS CAN OPERATE ON COLLECTIONS
A stream represents a sequence of elements on which one
or more operations can be performed.

A stream pipeline consists of:


a sequence of aggregate operations containing a source (e.g. a
list).
zero or more intermediate operations (e.g. filter, map) that
produce a new stream.
a terminal operation that produces a non-stream result (e.g.
forEach, sum, count, anymMatch).

22
EXAMPLES USING STREAMS
int total = orderlist.stream().mapToInt((Order od)
-> { return od.getCost(); }).sum();
int total = orderlist.stream().mapToInt( od ->
od.getCost()).sum(); //with valid omissions
----------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------

boolean exists = register.stream().anyMatch(nm ->


nm.getFamilyName().equals("Smith"));

----------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------

register.stream().filter(n ->
n.getFirstName().length() < 5).map(n ->
n.getFamilyName()).forEach(f ->
System.out.println(f)); //what will print out?

23
HOW DO I CHOOSE THE FORMAT OF A
LAMBDA EXPRESSION?
A lambda expression can be substituted wherever a
functional interface is expected:
⚫A functional interface contains only a single abstract method.
⚫The lambda expression should match the parameter-list and return
type of the abstract method.

Example – the Predicate<T> interface has a method


test, i.e.
public boolean test(T t)

The stream filter operation accepts a predicate as its


argument. The type parameter T is substituted with the
incoming element type of the stream.
24
A PREDICATE LAMBDA EXPRESSION
We could write:
register.stream().filter((Name n) -> {
return n.getFirstName().length() < 5;})...
//or omit parameter type, return and braces
register.stream().filter(n ->
n.getFirstName().length() < 5)...

In each case, you are defining a lambda expression that


accepts an incoming Name object and returns a boolean
value. This will run on each stream element.

This clearly matches the signature of the Predicate


interface's test method.
25
LAMBDA REQUIRED BY FOREACH METHOD
To execute the forEach method we may write:
register.forEach(n ->
System.out.println(n.getFullName());

By viewing the API we see that the forEach method


accepts an argument of type consumer.

The Consumer<T> interface has a method accept, i.e.


public void accept(T t)

Quite simply, it accepts the incoming element type and


performs a given operation, without having to return
anything.

26
CHOOSING AN ARRAYLIST OR ARRAY?
Use an array if:
 the size of the collection never changes.
 you collect a long sequence of primitive type values and you are
concerned about efficiency (auto-boxing takes time).

Otherwise, use an ArrayList!

We will rarely use arrays during the rest of the module


and instead will use the ArrayList class, or other
collection classes, e.g. maps or sets.

27
OVERRIDING EQUALS – COMMON MISTAKE
A common mistake is to set the parameter type to be
the same as the class type, instead of Object, e.g.

public boolean equals(Name obj) {

If you do this, it will not actually override the


equals(…) method inherited from the Object class. It
will instead overload it. To be safe, use the @Override
annotation, e.g.

@Override
public boolean equals(Object obj) {

28 28
NOTE: OVERLOADING METHODS
An overloaded method is simply a method with the same
name that is declared more than once with a different
parameter-list.

For example, there are actually lots of different versions


of println(…). Think about an ArrayList, there are
two add methods: add(E) & add(int, E).

Overloaded methods are completely different to


overridden methods, but it is worth being aware that if
you do not override a method, you will likely be
overloading it instead!

29 29
SO WHAT IS THE ISSUE?
If we accidently overload equals(Object) with our
own version then what is actually the issue?

After all… we can still use it to check two of our custom


Name objects for equality.

The issue is that other classes/methods may also use


equals(…) and they would use the inherited
equals(Object) version, not your own.

An example of this is the contains(…) method


belonging to the ArrayList class.

30 30
ARRAYLIST CONTAINS(...) METHOD
When you have an ArrayList instance populated with
objects of a given type, you can test if the list already
contains an object.

The contains(…) method uses the equals(…)


method to test objects for equality.
ArrayList<Name> names = new ArrayList<>();
names.add(new Name("Joe", "Bloggs");
Name n = new Name("Joe", "Bloggs");
if ( names.contains(n) )
//will evaluate true if the Name class
overrides equals(…)

31 31
ARRAYLIST REMOVE(OBJECT) METHOD
The equals method is used by other ArrayList methods
such as remove, which removes the provided object.

For example
//add lots of name objects
Name n = new Name("Joe", "Bloggs");

if ( names.remove(n) )
//name found and successfully removed
else
//name not found

32 32
SUGGESTED READING
Big Java : Early Objects (5th Ed.) Cay, S. Horstmann
⚫Chapter 6: Arrays and Array Lists
⚫Section 2.9.2: The null Reference

Java Tutorials hosted by Oracle


⚫http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
⚫http://docs.oracle.com/javase/tutorial/collections/implementations/list.html

For those interested in learning more about Streams e.g.


⚫http://docs.oracle.com/javase/tutorial/collections/streams/
⚫http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html
33 33
34
EXERCISE 4
4.1 Copy the Name class that you have created in exercise 3.2 to your
current Java project and then create a new class called "NameListTest“.
Create an ArrayList of type Name (i.e. List<Name> register = new
ArrayList<>();).
a. Add names of five students to the register.
b. Use the forEach method to output the full name of every Name element
in the list. You should use lambda expression.
c. Using stream().filter(...) create a stream pipeline to output names that
are of a length greater than 10 characters.

35 35
EXERCISE 4.2
4.2 Copy the Order that you have created the Lab to your current Java project and then
create a new class called “OrderListTest“.
Create an ArrayList of type Name (i.e. List<Order> orderList = new
ArrayList<>();).
a. Add five different orders to the orderList.
b. Use the forEach method to output the id and cost of each order. You should use lambda
expression.
c. Using stream().mapToInt(… ).sum(); create a stream pipeline to output the total
cost of the orders in the orderList.
.
Submission:
Upload your java files
NameListTest.java and OrderListTest.java to the google drive folder that your
have shared with the email ([email protected]) by 10:00 am, 7th July, 2021.

36 36

You might also like