Topic 11 of 28 · Android Native Developer

Topic 11 : Collections in Java - Queue

Lesson TL;DRTopic 11: Collections in Java Queue 📖 6 min read · 🎯 Advanced · 🧭 Prerequisites: collectionsinjavalist, androideventhandling Why this matters Picture this: you open a food delivery app and place an...
6 min read·advanced·java · android · collections · queue

Topic 11: Collections in Java - Queue

📖 6 min read · 🎯 Advanced · 🧭 Prerequisites: collections-in-java-list, android-event-handling

Why this matters

Picture this: you open a food delivery app and place an order. Behind the scenes, dozens of orders are arriving every second — and the kitchen has to process them in the exact order they came in. No skipping the line, no jumping ahead. That's not just fairness — it's correctness. If your app processes things out of order, you get bugs that are really hard to explain. In Java, the Queue collection is built exactly for this — First In, First Out, or FIFO. Let's see how it works and when you'll reach for it in your Android code.

What You'll Learn

  • Understand the Queue interface and the FIFO (First In, First Out) principle in Java
  • Implement a Queue<String> using LinkedList as the backing data structure
  • Use add(), poll(), and peek() to manage queue entries
  • Integrate a Java queue into a working Android Activity with a live UI

The Analogy

Picture a customer support hotline on a busy Monday morning. The first caller who dials in is the first one an agent picks up — nobody cuts the line, nobody gets skipped, and the agent always clears the oldest call before taking a new one. The queue of callers forms at the moment of first contact and dissolves one-by-one as each person is helped. A Java Queue works exactly this way: elements enter at the tail and leave from the head, preserving arrival order with mathematical certainty. Jump-the-line logic simply doesn't exist in this data structure unless you reach for a PriorityQueue — and even then you're trading FIFO for a defined ordering rule, not chaos.

Chapter 1: The Queue Interface and FIFO

A Queue in Java is an interface in the java.util package that enforces FIFO — First In, First Out ordering. Elements are inserted at the tail and retrieved from the head. This makes queues the right tool whenever processing order must mirror arrival order: print spoolers, network packet buffers, task schedulers, and support-ticket systems all rely on this guarantee.

Key Queue methods you will use constantly:

MethodBehavior on empty queueReturns
add(e)throws IllegalStateExceptionboolean
offer(e)returns falseboolean
poll()returns nullhead element or null
remove()throws NoSuchElementExceptionhead element
peek()returns nullhead element or null
element()throws NoSuchElementExceptionhead element

For Android work, prefer offer/poll/peek — they never throw on empty, which means no surprise crashes on the UI thread.

LinkedList is the most common Queue implementation in standard Java. It satisfies the Queue interface and handles unbounded growth gracefully, making it a natural fit for ticket-style scenarios where you don't know the maximum load in advance.

Chapter 2: Building the TicketManager

Create a new Android Studio project named TicketManager. The core logic lives in a dedicated TicketManager class that wraps the queue so the Activity doesn't touch the data structure directly.

import java.util.LinkedList;
import java.util.Queue;

public class TicketManager {
    private Queue<String> ticketQueue;

    public TicketManager() {
        ticketQueue = new LinkedList<>();
    }

    // Adds a new support ticket to the tail of the queue
    public void addTicket(String ticket) {
        ticketQueue.add(ticket);
        System.out.println("Ticket added: " + ticket);
    }

    // Removes and processes the head ticket; safe on empty queue
    public void processNextTicket() {
        String nextTicket = ticketQueue.poll();
        if (nextTicket != null) {
            System.out.println("Processing ticket: " + nextTicket);
        } else {
            System.out.println("No tickets to process.");
        }
    }

    // Returns the head ticket without removing it; returns null if empty
    public String peekNextTicket() {
        return ticketQueue.peek();
    }
}

Three things to note:

  1. Queue InitializationticketQueue = new LinkedList<>() assigns a LinkedList instance to the Queue<String> reference. The variable type is the interface; the runtime type is the implementation. This is standard Java polymorphism and lets you swap the backing structure later without changing the rest of the class.
  2. Adding TicketsaddTicket calls ticketQueue.add(ticket), which appends to the tail.
  3. Processing TicketsprocessNextTicket calls ticketQueue.poll(), which atomically removes and returns the head element, or returns null if the queue is empty.
  4. PeekingpeekNextTicket calls ticketQueue.peek(), which reads the head element without consuming it. Useful for displaying "up next" in the UI without advancing state.

Chapter 3: Integrating with an Android Activity

Now wire the TicketManager into a real Android UI. The layout gives the user an input field, an add button, a process button, and a status label.

<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/ticketInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter ticket"/>

    <Button
        android:id="@+id/addTicketButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add Ticket"/>

    <Button
        android:id="@+id/processTicketButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Process Next Ticket"/>

    <TextView
        android:id="@+id/ticketStatus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Ticket Status"/>

</LinearLayout>
// MainActivity.java
package com.example.ticketmanager;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private TicketManager ticketManager;
    private EditText ticketInput;
    private TextView ticketStatus;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ticketManager = new TicketManager();
        ticketInput = findViewById(R.id.ticketInput);
        ticketStatus = findViewById(R.id.ticketStatus);

        Button addTicketButton = findViewById(R.id.addTicketButton);
        addTicketButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String ticket = ticketInput.getText().toString();
                if (!ticket.isEmpty()) {
                    ticketManager.addTicket(ticket);
                    ticketInput.setText("");
                }
            }
        });

        Button processTicketButton = findViewById(R.id.processTicketButton);
        processTicketButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ticketManager.processNextTicket();
                ticketStatus.setText("Next Ticket: " + ticketManager.peekNextTicket());
            }
        });
    }
}

What each piece does:

  • addTicketButton click handler — reads the EditText, guards against empty input, calls addTicket, then clears the field so the user can enter the next one.
  • processTicketButton click handler — calls processNextTicket (which pops the head and logs it), then immediately calls peekNextTicket to show the new head in the ticketStatus label. If the queue is now empty, peek() returns null and the status shows "Next Ticket: null" — you'd want to guard that in a production app.
sequenceDiagram
    participant User
    participant MainActivity
    participant TicketManager
    participant Queue as LinkedList<String>

    User->>MainActivity: types "Bug #42", taps Add
    MainActivity->>TicketManager: addTicket("Bug #42")
    TicketManager->>Queue: add("Bug #42")
    Queue-->>TicketManager: ok (tail updated)

    User->>MainActivity: taps Process Next
    MainActivity->>TicketManager: processNextTicket()
    TicketManager->>Queue: poll()
    Queue-->>TicketManager: "Bug #42" (head removed)
    TicketManager-->>MainActivity: (logs "Processing ticket: Bug #42")
    MainActivity->>TicketManager: peekNextTicket()
    TicketManager->>Queue: peek()
    Queue-->>TicketManager: next head or null
    TicketManager-->>MainActivity: next ticket string
    MainActivity->>User: updates ticketStatus TextView

🧪 Try It Yourself

Task: Extend TicketManager with a viewAllTickets() method that returns a formatted string listing every pending ticket in queue order (head first), then display this string in a new TextView when a "View All" button is tapped.

Success criterion: After adding tickets "Bug #1", "Bug #2", and "Bug #3" in that order, tapping "View All" should display:

Pending: Bug #1, Bug #2, Bug #3

Starter snippet:

public String viewAllTickets() {
    if (ticketQueue.isEmpty()) {
        return "No pending tickets.";
    }
    StringBuilder sb = new StringBuilder("Pending: ");
    for (String ticket : ticketQueue) {
        sb.append(ticket).append(", ");
    }
    // Remove trailing ", "
    return sb.substring(0, sb.length() - 2);
}

Wire a new Button (@+id/viewAllButton) and TextView (@+id/allTicketsView) into the layout and call ticketManager.viewAllTickets() in its click handler.

🔍 Checkpoint Quiz

Q1. What does FIFO stand for, and which Queue method removes and returns the head element without throwing an exception on an empty queue?

Q2. Given the following code, what does output contain after execution?

Queue<String> q = new LinkedList<>();
q.add("alpha");
q.add("beta");
q.add("gamma");
q.poll();
String output = q.peek();

A) "alpha" B) "beta" C) "gamma" D) null

Q3. The processTicketButton click handler calls processNextTicket() and then peekNextTicket(). Why does it call peek after poll rather than before?

A) peek only works after poll is called B) To display the next ticket that will be processed, not the one just processed C) poll resets the queue so peek returns the first element again D) There is no functional difference; the order doesn't matter

Q4. You are building a notification delivery system. Notifications must be delivered in the order they were generated, and you need to handle the case where the queue is empty gracefully (no crashes). Which implementation best fits?

A) ArrayList with manual index tracking B) Queue<Notification> backed by LinkedList, using offer() and poll() C) Queue<Notification> backed by LinkedList, using add() and remove() D) HashMap<Integer, Notification> keyed by arrival timestamp

A1. FIFO = First In, First Out. The method is poll() — it returns null on an empty queue instead of throwing NoSuchElementException like remove() does.

A2. B) "beta". poll() removes "alpha" (the head). After that the head is "beta", and peek() returns it without removing it.

A3. B) To display the next ticket that will be processed. After poll() removes the just-processed ticket, peek() looks at the new head — i.e., the ticket that will be processed on the next button tap. Calling peek before poll would show the ticket about to be processed right now, which is less useful as a status message.

A4. B) Queue<Notification> backed by LinkedList, using offer() and poll(). offer/poll are the null-safe variants that don't throw on capacity or empty conditions, which is critical for UI-thread safety in Android.

🪞 Recap

  • A Java Queue enforces FIFO order — the first element in is the first element out.
  • LinkedList is the standard Queue implementation for unbounded, order-sensitive workloads.
  • add()/remove()/element() throw exceptions on failure; offer()/poll()/peek() return null or false — prefer the latter in Android code.
  • poll() removes and returns the head; peek() reads the head without removing it.
  • Wrapping the queue in a dedicated manager class (like TicketManager) keeps Activity code clean and the queue logic testable in isolation.

📚 Further Reading

Like this topic? It’s one of 28 in Android Native Developer.

Block your seat for ₹2,500 and join the next cohort.