Generics, Collections, and Core Data Structures

Queues and FIFO Processing

ReadingPreview

আপনি একটি free preview lesson দেখছেন।

Lesson Overview

Collections-এর মধ্যে List, Set, এবং Map আমরা already শিখেছি।

কিন্তু কিছু problem আছে যেখানে data শুধু store করলেই হয় না—processing order-ও গুরুত্বপূর্ণ।

Example:

First request আসে
↓
সেটি আগে process হবে

Second request আসে
↓
সেটি পরে process হবে

এই ordering model-কে বলা হয়:

FIFO

meaning:

First In, First Out

Java-তে FIFO-style processing-এর জন্য important abstraction হলো:

Queue<E>

এই lesson-এ আমরা শিখব:

  • What a queue is
  • FIFO ordering
  • Queue<E>
  • ArrayDeque
  • offer()
  • poll()
  • peek()
  • add()
  • remove()
  • element()
  • Queue traversal
  • Queue size and emptiness
  • Queue as an interface
  • Why ArrayDeque is usually a strong default
  • Queue vs List
  • Real backend-style queue use cases
  • Common mistakes
  • Designing queue-processing methods

What Is a Queue?

Imagine a line of people waiting at a counter।

The first person who joins the line should normally be served first।

Conceptually:

Front
↓
Sakib → Subu → Sumu → Nur
                      ↑
                     Back

If Sakib entered first, Sakib leaves first।

This behavior is:

FIFO

or:

First In, First Out

Queue Operations

A queue normally needs three fundamental operations:

Add an item to the back
Remove the item from the front
Inspect the item at the front

Conceptually:

offer → add to back
poll  → remove from front
peek  → inspect front

Java Queue<E>

Java provides:

java.util.Queue

Queue is an interface।

Example:

Queue<String> tasks;

This means:

A queue containing String values

But because Queue is an interface, we need an implementation।

A common implementation is:

ArrayDeque

Creating a Queue

import java.util.ArrayDeque;
import java.util.Queue;

public class Main {

    public static void main(String[] args) {
        Queue<String> tasks =
                new ArrayDeque<>();
    }
}

Notice the declaration:

Queue<String> tasks

and implementation:

new ArrayDeque<>()

This follows an important design principle:

Program to an abstraction
when the abstraction expresses what you need.

The variable promises queue behavior।

The implementation provides it।


Adding Elements with offer()

Example:

Queue<String> tasks =
        new ArrayDeque<>();

tasks.offer(
        "Send email"
);

tasks.offer(
        "Generate invoice"
);

tasks.offer(
        "Update report"
);

Conceptually:

Front
↓
Send email
Generate invoice
Update report
↑
Back

Why offer()?

For queue-style code, offer() communicates intent clearly:

Add this item to the queue.

Example:

tasks.offer(
        "Process enrollment"
);

Removing with poll()

poll() removes and returns the front element।

Example:

String task =
        tasks.poll();

If queue contains:

Send email
Generate invoice
Update report

then:

task = "Send email"

and queue becomes:

Generate invoice
Update report

FIFO in Action

Queue<String> tasks =
        new ArrayDeque<>();

tasks.offer(
        "First"
);

tasks.offer(
        "Second"
);

tasks.offer(
        "Third"
);

System.out.println(
        tasks.poll()
);

System.out.println(
        tasks.poll()
);

System.out.println(
        tasks.poll()
);

Output:

First
Second
Third

That is FIFO।


Inspecting with peek()

Sometimes we want to see the front element without removing it।

Use:

peek()

Example:

Queue<String> tasks =
        new ArrayDeque<>();

tasks.offer(
        "Send email"
);

tasks.offer(
        "Generate invoice"
);

String next =
        tasks.peek();

Now:

next = "Send email"

but the queue still contains both elements।


peek() vs poll()

peek()
→ inspect front
→ does not remove

poll()
→ returns front
→ removes it

Complete Example

import java.util.ArrayDeque;
import java.util.Queue;

public class Main {

    public static void main(String[] args) {
        Queue<String> tasks =
                new ArrayDeque<>();

        tasks.offer(
                "Send verification email"
        );

        tasks.offer(
                "Generate certificate"
        );

        tasks.offer(
                "Update learner progress"
        );

        System.out.println(
                "Next: "
                + tasks.peek()
        );

        while (
                !tasks.isEmpty()
        ) {
            String task =
                    tasks.poll();

            System.out.println(
                    "Processing: "
                    + task
            );
        }
    }
}

Output:

Next: Send verification email
Processing: Send verification email
Processing: Generate certificate
Processing: Update learner progress

What Happens on an Empty Queue?

Suppose:

Queue<String> tasks =
        new ArrayDeque<>();

Then:

tasks.poll()

returns:

null

and:

tasks.peek()

also returns:

null

This makes them convenient when absence is expected and handled।


Example

String task =
        tasks.poll();

if (
        task == null
) {
    System.out.println(
            "No task available."
    );
}

Queue Has Two Method Families

Java Queue provides two styles of operations।

One style returns a special value when an operation cannot be completed normally।

Examples:

offer()
poll()
peek()

Another style throws an exception in corresponding situations।

Examples:

add()
remove()
element()

Queue Method Pairs

The important pairs are:

Add:
add()
offer()

Remove:
remove()
poll()

Inspect:
element()
peek()

poll() vs remove()

On a non-empty queue, both remove the front element।

Example:

queue.poll();

and:

queue.remove();

But on an empty queue:

queue.poll()

returns:

null

while:

queue.remove()

throws:

NoSuchElementException

peek() vs element()

On a non-empty queue, both inspect the front।

But on an empty queue:

queue.peek()

returns:

null

while:

queue.element()

throws:

NoSuchElementException

offer() vs add()

For many general-purpose queue implementations, both successfully add elements।

But conceptually:

offer()

is designed for queue insertion where capacity restrictions may exist।

If an insertion cannot happen:

offer()

can report failure via its return value।

boolean added =
        queue.offer(
                value
        );

add() follows the general Collection contract and may throw an exception when insertion cannot be performed because of restrictions।

For ordinary queue-oriented code, offer() is often the clearest choice।


Recommended Queue Vocabulary

For queue-style processing, prefer learning this trio first:

offer()
poll()
peek()

Why?

Because they directly communicate queue behavior and handle empty-state inspection/removal without requiring exceptions as normal control flow।


Why ArrayDeque?

A strong general-purpose Queue implementation is:

ArrayDeque

Example:

Queue<String> queue =
        new ArrayDeque<>();

ArrayDeque supports efficient operations at both ends।

For ordinary FIFO queues, it is usually a better default than manually using an ArrayList as a queue।


Why Not ArrayList?

Technically, you could write:

List<String> queue =
        new ArrayList<>();

Add:

queue.add(
        task
);

Then remove the first element:

queue.remove(
        0
);

But removing index 0 from an ArrayList generally requires shifting later elements।

Conceptually:

[A, B, C, D]

remove A

[B, C, D]
 ↑  ↑  ↑
elements must shift

That makes it a poor default for repeated front-removal queue workloads।


Queue Expresses Intent

Compare:

List<String> tasks =
        new ArrayList<>();

with:

Queue<String> tasks =
        new ArrayDeque<>();

The second version tells another developer:

These values are processed in queue order.

Choosing the right collection is not only about performance।

It also communicates design intent।


Queue Order

A normal FIFO queue processes:

Insertion order

from the front।

Example:

queue.offer(
        "A"
);

queue.offer(
        "B"
);

queue.offer(
        "C"
);

Then:

queue.poll()

returns:

A

Queue Does Not Mean Arbitrary Index Access

A queue is not designed around:

queue.get(5)

because the abstraction is not:

Random access by index

It is:

Process the next item

This is a major conceptual difference from List


Queue Processing Pattern

One of the most common patterns is:

while (
        !queue.isEmpty()
) {
    T item =
            queue.poll();

    process(
            item
    );
}

Example:

while (
        !tasks.isEmpty()
) {
    String task =
            tasks.poll();

    System.out.println(
            task
    );
}

Using poll() Directly as the Condition

Another pattern:

String task;

while (
        (
                task = tasks.poll()
        ) != null
) {
    System.out.println(
            task
    );
}

This is legal Java।

But for beginner and many production contexts, the assignment inside the condition is less obvious।

Prefer clarity:

while (
        !tasks.isEmpty()
) {
    String task =
            tasks.poll();

    process(
            task
    );
}

unless the alternative clearly improves the code।


Queue Size

Because Queue extends Collection, common operations are available:

queue.size()
queue.isEmpty()
queue.clear()
queue.contains(...)

Example:

System.out.println(
        queue.size()
);

isEmpty()

Prefer:

queue.isEmpty()

over:

queue.size() == 0

because isEmpty() directly communicates the question being asked।


Queue Iteration

You can iterate over a queue:

for (
        String task
        : tasks
) {
    System.out.println(
            task
    );
}

But this does not remove the elements।

Traversal and queue consumption are different operations।


Inspecting vs Consuming

Consider:

for (
        String task
        : tasks
) {
    System.out.println(
            task
    );
}

After the loop:

Queue still contains the tasks.

But:

while (
        !tasks.isEmpty()
) {
    tasks.poll();
}

consumes them।


Queue Consumption Changes State

A queue is often a mutable workflow structure।

Example:

Before:

[A, B, C]

After:

queue.poll();

state becomes:

[B, C]

This mutation is part of the queue abstraction।


Example: Enrollment Processing

Suppose enrollment requests should be handled in arrival order।

Queue<String> enrollments =
        new ArrayDeque<>();

enrollments.offer(
        "Sakib"
);

enrollments.offer(
        "Subu"
);

enrollments.offer(
        "Sumu"
);

Processing:

while (
        !enrollments.isEmpty()
) {
    String learner =
            enrollments.poll();

    System.out.println(
            "Enrolling: "
            + learner
    );
}

Output:

Enrolling: Sakib
Enrolling: Subu
Enrolling: Sumu

Example: Support Requests

Imagine support requests arrive:

REQ-1001
REQ-1002
REQ-1003

A simple FIFO queue could be:

Queue<String> requests =
        new ArrayDeque<>();

requests.offer(
        "REQ-1001"
);

requests.offer(
        "REQ-1002"
);

requests.offer(
        "REQ-1003"
);

Next request:

requests.peek();

returns:

REQ-1001

Processing:

requests.poll();

removes:

REQ-1001

Backend Systems and Queues

The queue concept appears constantly in backend engineering।

Examples:

Background jobs
Email delivery
Payment processing
Event processing
Message brokers
Task scheduling
Request buffering
Batch processing

Java's in-memory Queue is not the same thing as a distributed message broker such as Kafka or RabbitMQ।

But the FIFO abstraction helps build the mental model।


In-Memory Queue vs Message Broker

An in-memory Java queue:

Queue<Task>

exists inside one running process।

If the process stops, that queue usually disappears unless separately persisted।

A message broker is a separate infrastructure component designed for concerns such as:

Durability
Distributed producers
Distributed consumers
Acknowledgement
Retries
Partitioning
Delivery guarantees

We are not teaching those systems here।

The important connection is simply:

Both can involve ordered work waiting to be processed.

FIFO Is Not Always Guaranteed Everywhere

Be careful with this statement:

Queue means FIFO

The Queue interface is used by multiple implementations, and some queues order elements differently।

For example:

PriorityQueue

does not process elements purely by insertion order।

It uses priority/natural ordering or a comparator।

We will study PriorityQueue later in the Algorithms module when discussing heaps।

For this lesson:

Queue + ArrayDeque

is our FIFO queue model।


Queue Is an Interface

This is worth reinforcing।

Queue<String> tasks =
        new ArrayDeque<>();

The variable type:

Queue<String>

defines the operations we want to depend on।

Implementation:

ArrayDeque<String>

provides them।

This means code like:

static void processAll(
        Queue<String> tasks
)

does not need to care whether a particular compatible implementation is used।


Passing a Queue to a Method

Example:

static void processAll(
        Queue<String> tasks
) {
    while (
            !tasks.isEmpty()
    ) {
        String task =
                tasks.poll();

        System.out.println(
                "Processing: "
                + task
        );
    }
}

Call:

processAll(
        tasks
);

Important: The Method Mutates the Queue

After:

processAll(
        tasks
);

the queue is empty because poll() removed every element।

This should be intentional।


Read-Only Inspection Method

If you only want to inspect:

static void printAll(
        Queue<String> tasks
) {
    for (
            String task
            : tasks
    ) {
        System.out.println(
                task
        );
    }
}

This does not consume the queue।


Method Naming Should Reveal Mutation

Compare:

printAll(...)

with:

processAll(...)

processAll() suggests work may happen and queue state may change।

When a method consumes a collection, its contract should make that clear।


Queue of Custom Objects

Queues become much more useful once they store domain objects।

Example:

record Task(
        long id,
        String description
) {
}

Then:

Queue<Task> tasks =
        new ArrayDeque<>();

Add:

tasks.offer(
        new Task(
                1,
                "Generate certificate"
        )
);

Process Domain Objects

Task task =
        tasks.poll();

if (
        task != null
) {
    System.out.println(
            task.description()
    );
}

The queue controls processing order।

The object carries the actual domain data।


Example: Course Publication Jobs

record PublicationJob(
        String courseCode
) {
}

Queue:

Queue<PublicationJob> jobs =
        new ArrayDeque<>();

jobs.offer(
        new PublicationJob(
                "JAVA-OOP"
        )
);

jobs.offer(
        new PublicationJob(
                "BACKEND-JAVA"
        )
);

Processing:

while (
        !jobs.isEmpty()
) {
    PublicationJob job =
            jobs.poll();

    System.out.println(
            "Publishing: "
            + job.courseCode()
    );
}

Null Elements and ArrayDeque

ArrayDeque does not permit null elements।

This is useful because:

poll()

and:

peek()

use null to indicate that no element exists।

Therefore:

queue.offer(
        null
);

with an ArrayDeque is invalid and results in a NullPointerException


Why Null Rejection Helps

If null values were allowed:

queue.poll() == null

could mean either:

Queue was empty

or:

Queue contained a null item

Rejecting null keeps the semantics clear।


Queue and Duplicate Values

Queues can normally contain duplicate elements।

Example:

Queue<String> queue =
        new ArrayDeque<>();

queue.offer(
        "EMAIL"
);

queue.offer(
        "EMAIL"
);

This is valid।

Unlike Set, a queue is not about uniqueness।

Its main concern is processing order।


Queue vs Set vs List

Think about the primary semantic question।

List

I need an ordered collection
and possibly index-based access.

Set

I need uniqueness.

Queue

I need items waiting to be processed
according to queue ordering.

Queue vs Map

A Map answers:

What value belongs to this key?

A Queue answers:

What item should be processed next?

These are fundamentally different abstractions।


Example: Breadth-First Processing Preview

Queues are especially important in algorithms involving:

Breadth-first traversal

For example, when processing a tree level by level:

Root
↓
Children
↓
Grandchildren

A queue keeps track of which node should be visited next।

We will study this idea later in algorithms/data structures।


Producer and Consumer Concept

A queue often creates a boundary between two roles:

Producer
Consumer

Producer adds work:

queue.offer(
        task
);

Consumer removes work:

Task task =
        queue.poll();

Conceptually:

Producer
   ↓
[ Queue ]
   ↓
Consumer

Simple Producer Example

static void submitTask(
        Queue<String> tasks,
        String task
) {
    tasks.offer(
            task
    );
}

Simple Consumer Example

static String takeNextTask(
        Queue<String> tasks
) {
    return tasks.poll();
}

This model appears repeatedly in concurrent and distributed systems।

Later, concurrent queues add thread-safety concerns।


This Queue Is Not Automatically Thread-Safe

ArrayDeque itself is not designed as a thread-safe shared queue for concurrent mutation by multiple threads without coordination।

Later in Modern Java we will study structures such as:

BlockingQueue
ConcurrentLinkedQueue

and concurrency concepts properly।

For now, assume:

Single-threaded use
or externally controlled access

Common Beginner Mistake 1: Using remove(0) on ArrayList

For repeated FIFO processing:

list.remove(
        0
);

is usually the wrong abstraction and can be inefficient।

Prefer:

Queue<T>

with an appropriate implementation।


Common Beginner Mistake 2: Confusing peek() with poll()

peek()

does not remove।

poll()

does।


Common Beginner Mistake 3: Expecting poll() to Throw on Empty Queue

queue.poll()

returns:

null

when empty।

If you want exception-based behavior:

queue.remove()

does that।

But exception-driven empty handling is usually unnecessary for normal queue consumption।


Common Beginner Mistake 4: Using remove() as a Normal Empty Check

Avoid patterns like:

try {
    queue.remove();
} catch (...) {
    // queue empty
}

when emptiness is expected।

Prefer:

poll()

or:

isEmpty()

depending on the use case।


Common Beginner Mistake 5: Assuming All Queue Implementations Are FIFO

PriorityQueue follows priority ordering।

Always understand the implementation semantics।

For FIFO:

ArrayDeque

is a strong choice।


Common Beginner Mistake 6: Iterating When You Intended to Consume

This:

for (
        Task task
        : queue
) {
    process(
            task
    );
}

does not remove elements।

If the processing contract means completed work should leave the queue, use queue removal operations intentionally।


Common Beginner Mistake 7: Consuming a Queue Accidentally

If you pass a queue into:

processAll(
        queue
);

and processAll() uses poll(), the caller's queue changes।

Remember:

Collections are mutable objects
and references are passed by value.

Both caller and method access the same queue object।


Common Beginner Mistake 8: Adding null

With:

ArrayDeque

do not insert null

Use real domain values, or model absence separately।


Practical Example — Enrollment Request Queue

import java.util.ArrayDeque;
import java.util.Queue;

public class Main {

    public static void main(String[] args) {
        Queue<String> enrollmentRequests =
                new ArrayDeque<>();

        submit(
                enrollmentRequests,
                "Sakib"
        );

        submit(
                enrollmentRequests,
                "Subu"
        );

        submit(
                enrollmentRequests,
                "Sumu"
        );

        System.out.println(
                "Waiting: "
                + enrollmentRequests.size()
        );

        processNext(
                enrollmentRequests
        );

        processNext(
                enrollmentRequests
        );

        System.out.println(
                "Next learner: "
                + enrollmentRequests.peek()
        );
    }

    static void submit(
            Queue<String> requests,
            String learner
    ) {
        requests.offer(
                learner
        );
    }

    static void processNext(
            Queue<String> requests
    ) {
        String learner =
                requests.poll();

        if (
                learner == null
        ) {
            System.out.println(
                    "No enrollment request."
            );

            return;
        }

        System.out.println(
                "Processing enrollment for "
                + learner
        );
    }
}

Output:

Waiting: 3
Processing enrollment for Sakib
Processing enrollment for Subu
Next learner: Sumu

Practical Example — Task Queue

import java.util.ArrayDeque;
import java.util.Queue;

public class Main {

    public static void main(String[] args) {
        Queue<Task> tasks =
                new ArrayDeque<>();

        tasks.offer(
                new Task(
                        1,
                        "Send welcome email"
                )
        );

        tasks.offer(
                new Task(
                        2,
                        "Generate certificate"
                )
        );

        tasks.offer(
                new Task(
                        3,
                        "Update analytics"
                )
        );

        processAll(
                tasks
        );

        System.out.println(
                "Remaining tasks: "
                + tasks.size()
        );
    }

    static void processAll(
            Queue<Task> tasks
    ) {
        while (
                !tasks.isEmpty()
        ) {
            Task task =
                    tasks.poll();

            System.out.println(
                    "Processing "
                    + task.id()
                    + ": "
                    + task.description()
            );
        }
    }

    record Task(
            long id,
            String description
    ) {
    }
}

Output:

Processing 1: Send welcome email
Processing 2: Generate certificate
Processing 3: Update analytics
Remaining tasks: 0

Practice 1 — Basic FIFO

Create a queue containing:

Java
Backend
System Design

Then remove and print every element।

Expected:

Java
Backend
System Design

Solution

Queue<String> courses =
        new ArrayDeque<>();

courses.offer(
        "Java"
);

courses.offer(
        "Backend"
);

courses.offer(
        "System Design"
);

while (
        !courses.isEmpty()
) {
    System.out.println(
            courses.poll()
    );
}

Practice 2 — Peek Without Removal

Given:

Queue<String> queue =
        new ArrayDeque<>();

queue.offer(
        "First"
);

queue.offer(
        "Second"
);

Print the next element without removing it।


Solution

System.out.println(
        queue.peek()
);

Queue still contains:

First
Second

Practice 3 — Empty Queue

What does this return?

Queue<String> queue =
        new ArrayDeque<>();

String value =
        queue.poll();

Answer

null

Practice 4 — Process Only One Item

Implement:

static String processNext(
        Queue<String> queue
)

It should return the next value or:

"No work"

when empty।


Solution

static String processNext(
        Queue<String> queue
) {
    String value =
            queue.poll();

    if (
            value == null
    ) {
        return "No work";
    }

    return value;
}

Practice 5 — Count Without Consuming

Given a queue, count its elements without removing them।

Solution

Use:

queue.size()

There is no reason to consume the queue just to count it।


Practice 6 — Print Without Consuming

Implement:

static void printQueue(
        Queue<String> queue
)

without removing values।


Solution

static void printQueue(
        Queue<String> queue
) {
    for (
            String value
            : queue
    ) {
        System.out.println(
                value
        );
    }
}

Practice 7 — Consume All

Implement:

static void clearByProcessing(
        Queue<String> queue
)

that prints and removes every item।


Solution

static void clearByProcessing(
        Queue<String> queue
) {
    while (
            !queue.isEmpty()
    ) {
        String value =
                queue.poll();

        System.out.println(
                value
        );
    }
}

Practice 8 — Predict the Output

Queue<Integer> numbers =
        new ArrayDeque<>();

numbers.offer(
        10
);

numbers.offer(
        20
);

numbers.offer(
        30
);

System.out.println(
        numbers.poll()
);

System.out.println(
        numbers.peek()
);

System.out.println(
        numbers.poll()
);

Answer

10
20
20

After first poll():

[20, 30]

peek() sees 20 but does not remove it।

Second poll() removes 20


Practice 9 — poll() vs remove()

What is the key empty-queue difference?

Answer

poll()
→ returns null

remove()
→ throws NoSuchElementException

Practice 10 — Choose the Collection

Which collection abstraction best matches each requirement?

A

Need unique course codes.

B

Need learner names in positional order with index access.

C

Need requests processed in arrival order.

Answers

A → Set
B → List
C → Queue

True or False

  1. FIFO means First In, First Out.
  2. Queue is a concrete class.
  3. ArrayDeque can be used as a FIFO Queue.
  4. offer() adds an element.
  5. poll() removes the front element.
  6. peek() removes the front element.
  7. poll() returns null on an empty queue.
  8. remove() returns null on an empty queue.
  9. Iterating over a queue automatically consumes it.
  10. Queues can contain duplicate values.
  11. ArrayDeque allows null elements.
  12. Every implementation of Queue must process strictly FIFO.
  13. A Queue is often a better abstraction than ArrayList.remove(0) for FIFO work.
  14. Queue processing patterns appear in backend systems.

Answers

1. True
2. False
3. True
4. True
5. True
6. False
7. True
8. False
9. False
10. True
11. False
12. False
13. True
14. True

Knowledge Check

Question 1

What does FIFO mean?

Question 2

What is the primary purpose of a Queue?

Question 3

What does offer() do?

Question 4

What is the difference between poll() and peek()?

Question 5

What happens when poll() is called on an empty queue?

Question 6

What happens when remove() is called on an empty queue?

Question 7

Why is Queue<String> queue = new ArrayDeque<>() often preferable to declaring the variable as ArrayDeque<String>?

Question 8

Why is repeatedly removing index 0 from ArrayList not a strong default queue implementation?

Question 9

Does iterating over a queue remove elements?

Question 10

Why does ArrayDeque reject null?

Question 11

Are all Queue implementations FIFO?

Question 12

Give three backend-style situations where queue semantics are useful.


Knowledge Check Answers

Answer 1

FIFO means:

First In, First Out

The earliest inserted item is normally processed first।

Answer 2

A Queue models values waiting to be processed according to a queue-specific ordering policy।

Answer 3

offer() attempts to add an element to the queue।

Answer 4

peek() returns the next element without removing it, while poll() returns and removes it।

Answer 5

It returns:

null

Answer 6

It throws:

NoSuchElementException

Answer 7

Because the code depends on the queue abstraction rather than unnecessarily coupling callers to one particular implementation।

Answer 8

Removing the first ArrayList element generally requires shifting later elements, and List does not communicate FIFO-processing intent as clearly as Queue

Answer 9

No।

Normal iteration only visits the elements।

Answer 10

Among other design reasons, this lets methods such as poll() and peek() use null unambiguously to represent an empty queue।

Answer 11

No।

For example:

PriorityQueue

uses priority-based ordering rather than simple FIFO insertion order।

Answer 12

Examples include:

Background jobs
Email processing
Task scheduling
Request buffering
Event processing

Lesson Summary

এই lesson-এ আমরা FIFO-style data processing এবং Java Queue abstraction শিখেছি।

We learned:

  • FIFO means First In, First Out
  • Queue<E> models data waiting to be processed
  • Queue is an interface
  • ArrayDeque is a strong general-purpose implementation for ordinary FIFO queues
  • offer() adds an element
  • poll() removes and returns the front element
  • peek() inspects the front without removing it
  • poll() and peek() return null for an empty queue
  • remove() and element() use exception-based behavior on empty queues
  • Queue traversal does not automatically consume elements
  • Queue-processing loops usually remove elements using poll()
  • Queue operations mutate the queue state
  • Queue parameters can be consumed by methods, so mutation should be intentional
  • ArrayDeque does not permit null
  • Queues can contain duplicate values
  • Queue expresses processing intent better than treating a List as an improvised queue
  • Not every Queue implementation is strictly FIFO
  • PriorityQueue will be studied later with heap-based algorithms
  • Queue semantics appear naturally in backend jobs, request handling, scheduling, and messaging concepts
  • ArrayDeque itself is not automatically a thread-safe work queue

The core model is:

Producer
   ↓
offer()
   ↓
[ Queue ]
   ↓
poll()
   ↓
Consumer

For a normal FIFO queue:

First item added
↓
First item processed

Next Lesson

পরবর্তী নতুন lesson:

Deque, Stack, and ArrayDeque

আমরা শিখব:

  • What a Deque is
  • Adding and removing from both ends
  • addFirst()
  • addLast()
  • removeFirst()
  • removeLast()
  • peekFirst()
  • peekLast()
  • Stack and LIFO behavior
  • push()
  • pop()
  • peek()
  • Why modern Java generally prefers Deque over legacy Stack
  • Using ArrayDeque as both Queue and Stack
  • Practical LIFO/FIFO use cases