Exceptions, Iteratations, Object Methods
Exceptions
- Syntax:
throw new ExceptionObject(parameter1, ...)
- example:
throw new IllegalArgumentException("can't add null");
- example:
Iterations
Enhanced for loop
Set<String> s = new HashSet<>();
...
for (String city : s) {
...
}
translates to an ugly, manual approach:
Set<String> s = new HashSet<>();
...
Iterator<String> seer = s.iterator();
while (seer.hasNext()) {
String city = seer.next();
...
}
- Does the Set interface have an iterator() method? (1)
- Does the Iterator interface have next/hasNext() methods? (2)
Implementation
Iterable: the interface making a class able to be iterated on, and requires the method iterator()
, which returns an Iterator object. Think of any iterable as the object on which the iterator is performing.
Iterator: the interface defining the object with methods to actually do that iteration. Think of an Iterator as a machine that you put onto an iterable that facilitates the iteration.
(1) The Set interface extends the Iterable interface, inheriting the abstract iterator()
method:
public interface Iterable<T> {
Iterator<T> iterator();
}
public interface Set<T> extends Iterable<T>{
...
}
(2) The Iterator interface specifies abstract methods next()
and hasNext()
:
public interface Iterator<T> {
boolean hasNext();
T next();
}
Example: iterable ArraySet class
Write a new class called ArraySetIterator, nested inside of ArraySet:
private class ArraySetIterator implements Iterator<T> {
private int wizPos; // index to keep track of position in the array
/* constructor */
public ArraySetIterator() {
wizPos = 0;
}
/* implement the abtract methods in Iterator interface */
public boolean hasNext() {
return wizPos < size;
}
public T next() {
T returnItem = items[wizPos];
wizPos += 1;
return returnItem;
}
}
- Different objects need to be created for different structures like linked lists.
Need to make ArrayMap implement the Iterable interface. The essential method of the Iterable interface is iterator()
, which returns an Iterator object for that class. We have to return an instance of our ArraySetIterator
above:
public Iterator<T> iterator() {
return new ArraySetIterator();
}
ArraySet
code:
import java.util.Iterator;
public class ArraySet<T> implements Iterable<T> {
private T[] items;
private int size; // the next item to be added will be at position size
public ArraySet() {
items = (T[]) new Object[100];
size = 0;
}
/* Returns true if this map contains a mapping for the specified key.
*/
public boolean contains(T x) {
for (int i = 0; i < size; i += 1) {
if (items[i].equals(x)) {
return true;
}
}
return false;
}
/* Associates the specified value with the specified key in this map.
Throws an IllegalArgumentException if the key is null. */
public void add(T x) {
if (x == null) {
throw new IllegalArgumentException("can't add null");
}
if (contains(x)) {
return;
}
items[size] = x;
size += 1;
}
/* Returns the number of key-value mappings in this map. */
public int size() {
return size;
}
/** returns an iterator (a.k.a. seer) into ME */
public Iterator<T> iterator() {
return new ArraySetIterator();
}
private class ArraySetIterator implements Iterator<T> {
private int wizPos;
public ArraySetIterator() {
wizPos = 0;
}
public boolean hasNext() {
return wizPos < size;
}
public T next() {
T returnItem = items[wizPos];
wizPos += 1;
return returnItem;
}
}
public static void main(String[] args) {
ArraySet<Integer> aset = new ArraySet<>();
aset.add(5);
aset.add(23);
aset.add(42);
//iteration
for (int i : aset) {
System.out.println(i);
}
}
}
Object Methods
toString()
- The
System.out.println()
function implicitly callstoString()
- The default
Object
class’stoString()
method prints the address
Need to provide our own toString()
method for our own classes:
- a less elegant solution that does string creations in a loop
@Override
public String toString() {
String returnString = "{";
for (int i = 0; i < size; i += 1) {
returnString += keys[i];
returnString += ", ";
}
returnString += "}";
return returnString;
}
- a better solution that uses
StringBuilder
that creates a string object that is mutable, so you can continue appending instead of creating new ones.
@Override
public String toString() {
StringBuilder returnSB = new StringBuilder("{");
for (int i = 0; i < size - 1; i += 1) {
returnSB.append(items[i].toString());
returnSB.append(", ");
}
returnSB.append(items[size - 1]);
returnSB.append("}");
return returnSB.toString();
}
equals()
==
compares the bits of memory address and.equals()
compares the content- By default,
equals(Object o)
acts like==
Our own equals()
:
/* In order to override, must take Object as input. Potentially can compare to more general objects */
@Override
public boolean equals(Object other) {
if (this == other) { // the memory addresses are the same (same object)
return true;
}
if (other == null) { // null is always not equal to this
return false;
}
if (other.getClass() != this.getClass()) { // if object of other type is compared to
return false;
}
ArraySet<T> o = (ArraySet<T>) other;
if (o.size() != this.size()) { // if size is different, not equal
return false;
}
for (T item : this) {
if (!o.contains(item)) { // final: if any content is different
return false;
}
}
return true;
}
Rules for Equals in Java:
equals
must be an equivalence relation:- reflexive:
x.equals(x)
is true - symmetric:
x.equals(y)
if and only ify.equals(x)
- transitive:
x.equals(y)
andy.equals(z)
impliesx.equals(z)
- reflexive:
- It must take an Object argument, in order to override the original
.equals()
method - It must be consistent: if
x.equals(y)
, then as long asx
andy
remain unchanged:x
must continue to equaly
x.equals(null)
must be false
Better toString()
String.join() takes in a String type delimiter and a iterable object and returns the string. List in this case, is iterable.
@Override
public String toString() {
List<String> listOfItems = new ArrayList<>();
for (T x : this) {
listOfItems.add(x.toString());
}
return "{" + String.join(", ", listOfItems) + "}";
}
of()
- Static method does not get the type parameter, so need to make the method generic.
Glerp... stuff
is called var arg<Glerp>
is the specified generic method type parameterArraySet<Glerp>
is the return type
public static <Glerp> ArraySet<Glerp> of(Glerp... stuff) {
ArraySet<Glerp> returnSet = new ArraySet<Glerp>();
for (Glerp x : stuff) {
returnSet.add(x);
}
return returnSet;