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, retornandotruese bem-sucedido oufalsecaso 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,BlockingDequee similares estão no pacotejava.util.concurrente 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
Can you explain more about the difference between add() and offer() methods?
How does the FIFO principle work in a real-world queue?
What are some practical uses of the Queue interface in Java?
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, retornandotruese bem-sucedido oufalsecaso 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,BlockingDequee similares estão no pacotejava.util.concurrente 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!