Implementing isEmpty, top, and pop

The isEmpty operation is one line: the stack is empty exactly when size is zero.

@Override
public boolean isEmpty() {
  return size == 0;
}

The top returns the item at arr[size - 1]. On an empty stack, it throws a NoSuchElementException.

@Override
public T top() {
  if (isEmpty()) {
    throw new NoSuchElementException();
  }
  return arr[size - 1];  // the top is at the end of the array
}

Notice that top calls isEmpty instead of comparing size to zero itself. Either way works. Reusing the method makes the code easier to read.

The pop operation follows:

@Override
public void pop() {
  if (isEmpty()) {
    throw new NoSuchElementException();
  }
  size--;
  arr[size] = null;  // clear the slot so the object can be garbage collected
}

You don’t have to clear the slot, but it is good practice.