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); } }