Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Fila | Estruturas de Dados Adicionais
Estruturas de Dados em Java

bookFila

Vamos falar sobre duas estruturas de dados bastante interessantes - Queue e Deque.

Queue

Comecemos com uma Queue. Imagine uma fila em uma loja durante uma promoção. Há 10 pessoas; a primeira pessoa está mais próxima das portas da loja do que as outras, e a décima pessoa está mais distante. Quando a primeira pessoa entra na loja, ela sai da fila, movendo assim toda a fila para a frente por uma pessoa. A Queue do Java opera com um princípio muito semelhante.

Assim, podemos implementar vários programas onde a lógica de fila é bem elaborada. Por exemplo, a implementação de um quadro com planos e tarefas.

Mas primeiro, vamos dar uma olhada nos métodos básicos para trabalhar com uma Queue.

Queue é uma interface da qual a classe LinkedList herda, com a qual você já está familiarizado, então usaremos esta implementação.

Nota

Note que uma implementação de classe (como LinkedList) pode herdar de certas interfaces e implementar métodos dessas interfaces.

Dessa forma, usamos a interface como o tipo do objeto, mas a implementação do objeto será LinkedList porque é uma implementação específica desse objeto. (Lembre-se de que não podemos criar objetos com base em uma interface, certo?)

Exemplo:

example.java

example.java

copy
1234
// `LinkedList` as implementation of the `List` interface: List<T> list = new LinkedList<>(); // `LinkedList` as implementation of the `Queue` interface: Queue<T> queue = new LinkedList<>();

Dessa forma, podemos tornar nossa aplicação muito flexível ao usar várias implementações da mesma interface.

Mas voltemos aos métodos de trabalhar com Queue.

Métodos

Alguns métodos-chave da interface Queue são:

  • add(element): Adiciona um elemento à fila, lançando uma exceção se a operação não for possível.
  • offer(element): Adiciona um elemento à fila, retornando true se bem-sucedido ou false caso contrário.

Você pode notar que esses métodos fazem essencialmente a mesma coisa. No entanto, a principal diferença é a segurança do método offer. Em caso de uma adição de elemento inadequada, o método offer não lançará uma exceção e não interromperá a execução do programa.

Mas no momento, essa característica não é de grande interesse para nós, já que uma Queue regular não é limitada. Contudo, existe uma estrutura chamada BlockingQueue, que possui uma restrição no número de elementos; nesse caso, esses métodos terão uma diferença notável.

Vamos olhar um exemplo:

main.java

main.java

copy
1234567891011121314
package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.add("One"); queue.add("Two"); queue.add("Three"); System.out.println("Queue: " + queue); } }

Como você pode ver, ao utilizar o método add() e tentar adicionar um elemento que não se encaixa na fila, o programa lança um erro, terminando a execução de maneira inesperada. Vamos tentar a mesma operação, mas com um método mais seguro - offer():

main.java

main.java

copy
1234567891011121314
package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); } }

Como você pode ver, o elemento não foi adicionado à fila, mas também não gerou uma exceção. Portanto, podemos considerar que lidamos com o erro de maneira elegante. Podemos tratar exceções de maneiras diferentes usando uma estrutura como try-catch, mas discutiremos isso mais tarde.

Nota

Estruturas de dados como BlockingQueue, BlockingDeque e similares estão no pacote java.util.concurrent e são usadas para programação multithread. Aprenderemos sobre multithreading em Java em cursos futuros.

Vamos passar para os próximos métodos:

Métodos de remoção

  • remove(): Remove e retorna o elemento do início da fila, lançando uma exceção se a fila estiver vazia.
  • poll(): Remove e retorna o elemento do início da fila, retornando nulo se a fila estiver vazia.

Esses métodos executam a função precisamente como se a primeira pessoa da fila entrasse na loja e saísse da fila. Aqui, o princípio FIFO (First In, First Out - Primeiro a Entrar, Primeiro a Sair) é aplicado. Em outras palavras, o elemento que foi adicionado primeiro à fila será o primeiro a ser removido.

Aqui, você pode também observar a diferença entre esses dois métodos. O método poll() é mais utilizado do que o método remove() porque é mais seguro e não lança exceções.

Vamos dar uma olhada em um exemplo:

main.java

main.java

copy
123456789101112131415
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.remove(); queue.remove(); System.out.println("Queue after removal operation: " + queue); } }

Como você pode ver, o programa lança uma NoSuchElementException porque estamos tentando remover um elemento de uma fila vazia. Para evitar tal exceção, é melhor usar o método poll():

main.java

main.java

copy
123456789101112131415
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.poll(); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }

Agora, nós removemos um elemento da fila com segurança, e nenhuma exceção foi lançada quando tentamos remover um elemento de uma lista vazia. Legal!

A funcionalidade de poll() retornar null pode ser usada, por exemplo, em um loop while(). Vamos olhar um exemplo:

main.java

main.java

copy
1234567891011121314151617181920
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.poll() != null) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }

Dessa forma, podemos remover todos os elementos da fila utilizando um laço. Lembre-se de que o primeiro elemento que entrou na fila é o que é removido! Por exemplo, no caso do exemplo acima, o elemento com os dados "One" foi removido primeiro. O princípio FIFO (First In, First Out - Primeiro a Entrar, Primeiro a Sair) é demonstrado abaixo:

main.java

main.java

copy
123456789101112131415161718
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }

Ótimo, podemos prosseguir para os métodos que retornam o primeiro e o último elementos:

  • element(): Retorna, mas não remove, o elemento do início da fila, lançando uma exceção se a fila estiver vazia.
  • peek(): Retorna, mas não remove, o elemento do início da fila, retornando null se a fila estiver vazia.

Bem, acho que não preciso explicar pela terceira vez que usar o método peek() é muito melhor, pois é mais seguro e não lançará uma exceção.

Vamos olhar um exemplo de uso:

main.java

main.java

copy
12345678910111213141516
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); System.out.println("The first element in the queue: " + queue.peek()); System.out.println("Queue after the `peek()` method: " + queue); } }

Você pode combinar este método com outros métodos de fila. Por exemplo, se temos uma fila com cinco elementos e precisamos remover todos os elementos até o quarto (inclusive), vamos verificar a implementação de tal operação:

main.java

main.java

copy
123456789101112131415161718192021
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (!queue.peek().equals("Four")) { queue.poll(); } queue.poll(); System.out.println("Queue after removal operation: " + queue); } }

Utilizamos um laço com uma condição baseada no método peek(). Podemos otimizar significativamente este laço utilizando o método contains(). Este método retorna true se o elemento especificado estiver presente na fila e false se não estiver.

Vamos melhorar o código acima:

main.java

main.java

copy
1234567891011121314151617181920
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.contains("Four")) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }

Aqui, definimos uma única condição para o loop while. Conseguimos remover com sucesso todos os elementos até e incluindo o elemento "Quatro".

Nos próximos capítulos, você aprenderá sobre outra estrutura de dados semelhante - Deque, e também escreverá sua própria implementação de uma aplicação Gerenciador de Tarefas.

1. O que é uma Queue em Java?

2. Qual interface representa uma Fila no Framework de Coleções do Java?

3. Qual é o propósito do método offer() na interface Queue?

4. O que o método poll() faz na interface Queue?

5. Qual classe no pacote java.util.concurrent do Java representa uma fila bloqueante com limite?

6. O que acontece se você tentar adicionar um elemento a uma fila cheia usando o método add()?

question mark

O que é uma Queue em Java?

Select the correct answer

question mark

Qual interface representa uma Fila no Framework de Coleções do Java?

Select the correct answer

question mark

Qual é o propósito do método offer() na interface Queue?

Select the correct answer

question mark

O que o método poll() faz na interface Queue?

Select the correct answer

question mark

Qual classe no pacote java.util.concurrent do Java representa uma fila bloqueante com limite?

Select the correct answer

question mark

O que acontece se você tentar adicionar um elemento a uma fila cheia usando o método add()?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 1

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

Awesome!

Completion rate improved to 4

bookFila

Deslize para mostrar o menu

Vamos falar sobre duas estruturas de dados bastante interessantes - Queue e Deque.

Queue

Comecemos com uma Queue. Imagine uma fila em uma loja durante uma promoção. Há 10 pessoas; a primeira pessoa está mais próxima das portas da loja do que as outras, e a décima pessoa está mais distante. Quando a primeira pessoa entra na loja, ela sai da fila, movendo assim toda a fila para a frente por uma pessoa. A Queue do Java opera com um princípio muito semelhante.

Assim, podemos implementar vários programas onde a lógica de fila é bem elaborada. Por exemplo, a implementação de um quadro com planos e tarefas.

Mas primeiro, vamos dar uma olhada nos métodos básicos para trabalhar com uma Queue.

Queue é uma interface da qual a classe LinkedList herda, com a qual você já está familiarizado, então usaremos esta implementação.

Nota

Note que uma implementação de classe (como LinkedList) pode herdar de certas interfaces e implementar métodos dessas interfaces.

Dessa forma, usamos a interface como o tipo do objeto, mas a implementação do objeto será LinkedList porque é uma implementação específica desse objeto. (Lembre-se de que não podemos criar objetos com base em uma interface, certo?)

Exemplo:

example.java

example.java

copy
1234
// `LinkedList` as implementation of the `List` interface: List<T> list = new LinkedList<>(); // `LinkedList` as implementation of the `Queue` interface: Queue<T> queue = new LinkedList<>();

Dessa forma, podemos tornar nossa aplicação muito flexível ao usar várias implementações da mesma interface.

Mas voltemos aos métodos de trabalhar com Queue.

Métodos

Alguns métodos-chave da interface Queue são:

  • add(element): Adiciona um elemento à fila, lançando uma exceção se a operação não for possível.
  • offer(element): Adiciona um elemento à fila, retornando true se bem-sucedido ou false caso contrário.

Você pode notar que esses métodos fazem essencialmente a mesma coisa. No entanto, a principal diferença é a segurança do método offer. Em caso de uma adição de elemento inadequada, o método offer não lançará uma exceção e não interromperá a execução do programa.

Mas no momento, essa característica não é de grande interesse para nós, já que uma Queue regular não é limitada. Contudo, existe uma estrutura chamada BlockingQueue, que possui uma restrição no número de elementos; nesse caso, esses métodos terão uma diferença notável.

Vamos olhar um exemplo:

main.java

main.java

copy
1234567891011121314
package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.add("One"); queue.add("Two"); queue.add("Three"); System.out.println("Queue: " + queue); } }

Como você pode ver, ao utilizar o método add() e tentar adicionar um elemento que não se encaixa na fila, o programa lança um erro, terminando a execução de maneira inesperada. Vamos tentar a mesma operação, mas com um método mais seguro - offer():

main.java

main.java

copy
1234567891011121314
package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); } }

Como você pode ver, o elemento não foi adicionado à fila, mas também não gerou uma exceção. Portanto, podemos considerar que lidamos com o erro de maneira elegante. Podemos tratar exceções de maneiras diferentes usando uma estrutura como try-catch, mas discutiremos isso mais tarde.

Nota

Estruturas de dados como BlockingQueue, BlockingDeque e similares estão no pacote java.util.concurrent e são usadas para programação multithread. Aprenderemos sobre multithreading em Java em cursos futuros.

Vamos passar para os próximos métodos:

Métodos de remoção

  • remove(): Remove e retorna o elemento do início da fila, lançando uma exceção se a fila estiver vazia.
  • poll(): Remove e retorna o elemento do início da fila, retornando nulo se a fila estiver vazia.

Esses métodos executam a função precisamente como se a primeira pessoa da fila entrasse na loja e saísse da fila. Aqui, o princípio FIFO (First In, First Out - Primeiro a Entrar, Primeiro a Sair) é aplicado. Em outras palavras, o elemento que foi adicionado primeiro à fila será o primeiro a ser removido.

Aqui, você pode também observar a diferença entre esses dois métodos. O método poll() é mais utilizado do que o método remove() porque é mais seguro e não lança exceções.

Vamos dar uma olhada em um exemplo:

main.java

main.java

copy
123456789101112131415
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.remove(); queue.remove(); System.out.println("Queue after removal operation: " + queue); } }

Como você pode ver, o programa lança uma NoSuchElementException porque estamos tentando remover um elemento de uma fila vazia. Para evitar tal exceção, é melhor usar o método poll():

main.java

main.java

copy
123456789101112131415
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.poll(); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }

Agora, nós removemos um elemento da fila com segurança, e nenhuma exceção foi lançada quando tentamos remover um elemento de uma lista vazia. Legal!

A funcionalidade de poll() retornar null pode ser usada, por exemplo, em um loop while(). Vamos olhar um exemplo:

main.java

main.java

copy
1234567891011121314151617181920
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.poll() != null) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }

Dessa forma, podemos remover todos os elementos da fila utilizando um laço. Lembre-se de que o primeiro elemento que entrou na fila é o que é removido! Por exemplo, no caso do exemplo acima, o elemento com os dados "One" foi removido primeiro. O princípio FIFO (First In, First Out - Primeiro a Entrar, Primeiro a Sair) é demonstrado abaixo:

main.java

main.java

copy
123456789101112131415161718
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }

Ótimo, podemos prosseguir para os métodos que retornam o primeiro e o último elementos:

  • element(): Retorna, mas não remove, o elemento do início da fila, lançando uma exceção se a fila estiver vazia.
  • peek(): Retorna, mas não remove, o elemento do início da fila, retornando null se a fila estiver vazia.

Bem, acho que não preciso explicar pela terceira vez que usar o método peek() é muito melhor, pois é mais seguro e não lançará uma exceção.

Vamos olhar um exemplo de uso:

main.java

main.java

copy
12345678910111213141516
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); System.out.println("The first element in the queue: " + queue.peek()); System.out.println("Queue after the `peek()` method: " + queue); } }

Você pode combinar este método com outros métodos de fila. Por exemplo, se temos uma fila com cinco elementos e precisamos remover todos os elementos até o quarto (inclusive), vamos verificar a implementação de tal operação:

main.java

main.java

copy
123456789101112131415161718192021
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (!queue.peek().equals("Four")) { queue.poll(); } queue.poll(); System.out.println("Queue after removal operation: " + queue); } }

Utilizamos um laço com uma condição baseada no método peek(). Podemos otimizar significativamente este laço utilizando o método contains(). Este método retorna true se o elemento especificado estiver presente na fila e false se não estiver.

Vamos melhorar o código acima:

main.java

main.java

copy
1234567891011121314151617181920
package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.contains("Four")) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }

Aqui, definimos uma única condição para o loop while. Conseguimos remover com sucesso todos os elementos até e incluindo o elemento "Quatro".

Nos próximos capítulos, você aprenderá sobre outra estrutura de dados semelhante - Deque, e também escreverá sua própria implementação de uma aplicação Gerenciador de Tarefas.

1. O que é uma Queue em Java?

2. Qual interface representa uma Fila no Framework de Coleções do Java?

3. Qual é o propósito do método offer() na interface Queue?

4. O que o método poll() faz na interface Queue?

5. Qual classe no pacote java.util.concurrent do Java representa uma fila bloqueante com limite?

6. O que acontece se você tentar adicionar um elemento a uma fila cheia usando o método add()?

question mark

O que é uma Queue em Java?

Select the correct answer

question mark

Qual interface representa uma Fila no Framework de Coleções do Java?

Select the correct answer

question mark

Qual é o propósito do método offer() na interface Queue?

Select the correct answer

question mark

O que o método poll() faz na interface Queue?

Select the correct answer

question mark

Qual classe no pacote java.util.concurrent do Java representa uma fila bloqueante com limite?

Select the correct answer

question mark

O que acontece se você tentar adicionar um elemento a uma fila cheia usando o método add()?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 1
some-alt