Could you review this implementation of a queue data structure according to the principles of Object Oriented Programming and Clean Code?
import java.util.ArrayList;
public class SecurityCheckQueue<E extends ByAir> {
private ArrayList<E> queue;
public SecurityCheckQueue() {
queue = new ArrayList<E>();
}
public int getQueueLength() {
return queue.size();
}
public E peek() {
validateLength();
return queue.get(0);
}
public void enqueue(E elem) {
if (elem == null)
throw new IllegalArgumentException("Null");
queue.add(elem);
}
public E dequeue() {
validateLength();
return queue.remove(0);
}
public void validateLength() {
if (getQueueLength() == 0)
throw new IllegalStateException("Empty queue");
}
private void checkFlight(String flight) {
if (flight == null)
throw new IllegalArgumentException("Null");
}
private ArrayList<E> selectByFlight(String flight) {
checkFlight(flight);
ArrayList<E> out = new ArrayList<E>();
for (E elem : queue) {
if (elem.getFlightNumber().equals(flight))
out.add(elem);
}
return out;
}
private void removeFromQueue(ArrayList<E> elements) {
queue.removeAll(elements);
}
public void cancelFlight(String flight) {
checkFlight(flight);
validateLength();
ArrayList<E> elements = selectByFlight(flight);
removeFromQueue(elements);
}
public void expedite(String flight) {
checkFlight(flight);
validateLength();
ArrayList<E> elements = selectByFlight(flight);
removeFromQueue(elements);
queue.addAll(0, elements);
}
public void delay(String flight) {
checkFlight(flight);
validateLength();
ArrayList<E> elements = selectByFlight(flight);
removeFromQueue(elements);
queue.addAll(elements);
}
}