Fila
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
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, retornandotrue
se bem-sucedido oufalse
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
1234567891011121314package 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
1234567891011121314package 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 pacotejava.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
123456789101112131415package 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
123456789101112131415package 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
1234567891011121314151617181920package 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
123456789101112131415161718package 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
12345678910111213141516package 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
123456789101112131415161718192021package 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
1234567891011121314151617181920package 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()
?
Obrigado pelo seu feedback!
Pergunte à IA
Pergunte à IA
Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo
Awesome!
Completion rate improved to 4
Fila
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
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, retornandotrue
se bem-sucedido oufalse
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
1234567891011121314package 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
1234567891011121314package 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 pacotejava.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
123456789101112131415package 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
123456789101112131415package 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
1234567891011121314151617181920package 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
123456789101112131415161718package 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
12345678910111213141516package 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
123456789101112131415161718192021package 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
1234567891011121314151617181920package 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()
?
Obrigado pelo seu feedback!