Explain Codes LogoExplain Codes Logo

How do I use a PriorityQueue?

java
priorityqueue
comparator
lambda
Alex KataevbyAlex KataevยทAug 11, 2024
โšกTLDR

The PriorityQueue in Java sorts objects based on their natural order or by a custom Comparator. Method offer() adds elements, poll() removes them, and peek() views the front:

PriorityQueue<Integer> pq = new PriorityQueue<>(); pq.offer(2); pq.offer(1); System.out.println(pq.poll()); // Prints 1 ๐Ÿ˜Ž

When dealing with objects, create a Comparator to determine their priority:

PriorityQueue<Task> tasks = new PriorityQueue<>((t1, t2) -> t1.priority - t2.priority); tasks.offer(new Task(1, "Urgent")); // High prio task, no coffee break yet ! System.out.println(tasks.poll().description); // Prints "Urgent"

With capacity restrictions, offer() inserts or returns false on failure, while add() throws an exception. If the queue is bounded, offer() is a safer bet.

In-depth insights

Custom sorting with objects

With custom objects in a PriorityQueue, you need a Comparator for sorting:

class User { String name; int reputation; User(String name, int reputation) { this.name = name; this.reputation = reputation; } } // StackOverflow in a queue, reputation gets you first! ๐Ÿ˜ PriorityQueue<User> usersQueue = new PriorityQueue<>(Comparator.comparingInt(user -> user.reputation)); usersQueue.offer(new User("Alice", 9001)); usersQueue.offer(new User("Bob", 5000)); User topUser = usersQueue.poll(); System.out.println(topUser.name); // Prints "Alice"

Highest priority first

To create a max-priority queue (highest value out first), use Collections.reverseOrder() or Comparator.reversed(). So much for humbleness, it's your time to shine at the top! โœจ

PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Collections.reverseOrder()); // or for custom objects PriorityQueue<User> maxUserQueue = new PriorityQueue<>(Comparator.comparingInt(user -> user.reputation).reversed());

Concise comparator with lambdas

You can write Comparator in a more compact style using lambda expressions or method references. Because you've got important coding to do and every keystroke matters! โฑ๏ธ

// With lambda PriorityQueue<String> lengthQueue = new PriorityQueue<>((s1, s2) -> s1.length() - s2.length()); // With method reference PriorityQueue<String> lengthQueueMR = new PriorityQueue<>(Comparator.comparingInt(String::length));

Deciding between offer() and add()

The offer() method returns a boolean upon failure, making it the preferred choice for capacity-limited scenarios, so you won't rudely hit a wall when the room is full! ๐Ÿ˜ฎ

if (!boundedQueue.offer(element)) { // Oops, no more room for more elements! Handle the error }

Alternatively, add() can throw an IllegalStateException when you're not concerned with queue capacity or you want to catch exceptions with style:

try { unboundedQueue.add(element); } catch (IllegalStateException e) { // Well, trying to overload won't work here. Do something about it. }

Design and quirks to keep in mind

Preserving order in PriorityQueue

The iterative order of PriorityQueue elements is not necessarily the same as the priority-ordered output guarantee. To extract elements in guaranteed priority order, always use poll():

while (!pq.isEmpty()) { System.out.println(pq.poll()); // See you later, alligator ๐ŸŠ }

Extending PriorityQueue

It's best to use composition over inheritance when modifying the PriorityQueue's features to prevent side effects and keep momma PriorityQueue happy. ๐Ÿ˜Š

Wondering about null

PriorityQueue does not permit null elements. Adding null brings up a NullPointerException, keeping your queue safe and squeaky clean. ๐Ÿšท

try { pq.offer(null); } catch (NullPointerException e) { // Nulls aren't allowed. We prefer something over nothing! }