Uma fila regular segue uma estrutura FIFO (first in first out). Isso significa que se 3 mensagens - m1, m2 e m3 - entrarem na fila nessa ordem, elas sairão da fila exatamente na mesma ordem.

Por que precisamos de filas?

Digamos que temos produtores de dados (por exemplo, quando um usuário clica em uma página da web) que são extremamente rápidos. Mas então queremos consumir esses dados em um ritmo mais lento depois.

Nesse caso, o produtor colocaria todas as mensagens na fila e um consumidor as consumiria mais tarde da fila em um ritmo mais lento.

O que é uma fila de prioridade?

Como mencionado anteriormente, uma fila regular possui uma estrutura de primeiro a entrar, primeiro a sair. Mas, em alguns cenários, queremos processar mensagens em uma fila com base em sua prioridade e não em quando a mensagem entrou na fila.

As filas de prioridade ajudam os consumidores a consumir as mensagens de prioridade mais alta primeiro, seguidas pelas mensagens de prioridade mais baixa.

Filas prioritárias em Java

Agora vamos ver um código Java real que nos mostrará como usar as filas de prioridade.

Filas prioritárias com pedidos naturais

Aqui está um código mostrando como criar uma fila de prioridade simples para seqüências de caracteres

private static void testStringsNaturalOrdering() {        Queue testStringsPQ = new PriorityQueue<>();        testStringsPQ.add("abcd");        testStringsPQ.add("1234");        testStringsPQ.add("23bc");        testStringsPQ.add("zzxx");        testStringsPQ.add("abxy");        System.out.println("Strings Stored in Natural Ordering in a Priority Queuen");        while (!testStringsPQ.isEmpty()) {            System.out.println(testStringsPQ.poll());        }    }

A primeira linha nos diz que estamos criando uma fila de prioridade:

Queue testStringsPQ = new PriorityQueue<>();

PriorityQueue está disponível no pacote java.util.

Em seguida, adicionamos 5 strings em ordem aleatória na fila de prioridade. Para isso, usamos o adicionar() função como mostrado abaixo:

testStringsPQ.add("abcd");testStringsPQ.add("1234");testStringsPQ.add("23bc");testStringsPQ.add("zzxx");testStringsPQ.add("abxy");

Para obter o item mais recente da fila, usamos o votação() função como mostrado abaixo:

testStringsPQ.poll()

votação() nos fornecerá o item mais recente e também o removerão da fila. Se quisermos obter o item mais recente na fila sem removê-lo, podemos usar o olhadinha() função:

testStringsPQ.peek()

Por fim, imprimimos todos os elementos da fila usando a função poll () como mostrado abaixo:

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

Aqui está a saída do programa acima:

123423bcabcdabxyzzxx

Como não dissemos à fila de prioridade como priorizar seu conteúdo, ela utilizou uma ordem natural padrão. Nesse caso, ele retornou os dados na ordem crescente das strings. Essa não é a mesma ordem em que os itens foram adicionados à fila.

Que tal ter um pedido personalizado?

Isso também é possível, e podemos fazê-lo com a ajuda de um comparador.

Vamos criar uma fila de prioridade inteira agora. Mas desta vez vamos obter o resultado em ordem decrescente de valor.

Para conseguir isso, primeiro precisamos criar um comparador inteiro:

 static class CustomIntegerComparator implements Comparator {        @Override        public int compare(Integer o1, Integer o2) {            return o1 < o2 ? 1 : -1;        }    }

Para criar um comparador, implementamos o comparador interface e substitua o comparar método.

Usando o1 obteremos o resultado em ordem decrescente. Se tivéssemos usado o1> o2? 1: -1, então teríamos obtido o resultado em ordem crescente

Agora que temos o comparador, precisamos adicioná-lo à fila de prioridade. Podemos fazer isso assim:

Queue testIntegersPQ = new PriorityQueue<>(new CustomIntegerComparator());

Aqui está o restante do código que adiciona elementos à fila de prioridade e os imprime:

   testIntegersPQ.add(11);        testIntegersPQ.add(5);        testIntegersPQ.add(-1);        testIntegersPQ.add(12);        testIntegersPQ.add(6);        System.out.println("Integers stored in reverse order of priority in a Priority Queuen");        while (!testIntegersPQ.isEmpty()) {            System.out.println(testIntegersPQ.poll());        }

A saída do programa acima é fornecida abaixo:

121165-1

Podemos ver que o comparador fez seu trabalho bem. Agora a fila de prioridade está nos fornecendo os números inteiros em ordem decrescente.

Fila prioritária com objetos Java

Até o momento, vimos como podemos usar strings e números inteiros com filas de prioridade.

Em aplicativos da vida real, geralmente estaríamos usando filas de prioridade com objetos Java personalizados.

Vamos primeiro criar uma classe chamada CustomerOrder que é usada para armazenar detalhes do pedido do cliente:

public class CustomerOrder implements Comparable {    private int orderId;    private double orderAmount;    private String customerName;    public CustomerOrder(int orderId, double orderAmount, String customerName) {        this.orderId = orderId;        this.orderAmount = orderAmount;        this.customerName = customerName;    }    @Override    public int compareTo(CustomerOrder o) {        return o.orderId > this.orderId ? 1 : -1;    }    @Override    public String toString() {        return "orderId:" + this.orderId + ", orderAmount:" + this.orderAmount + ", customerName:" + customerName;    }    public double getOrderAmount() {        return orderAmount;    }}

Esta é uma classe Java simples para armazenar pedidos de clientes. Esta classe implementa interface comparável, para que possamos decidir com que base esse objeto precisa ser pedido na fila de prioridade.

A encomenda é decidida pelo comparado a função no código acima. A linha o.orderId> this.orderId? 1: -1 instrui que os pedidos devem ser classificados com base na ordem decrescente do orderId campo

Abaixo está o código que cria uma fila de prioridade para o objeto CustomerOrder:

CustomerOrder c1 = new CustomerOrder(1, 100.0, "customer1");CustomerOrder c2 = new CustomerOrder(3, 50.0, "customer3");CustomerOrder c3 = new CustomerOrder(2, 300.0, "customer2");Queue customerOrders = new PriorityQueue<>();customerOrders.add(c1);customerOrders.add(c2);customerOrders.add(c3);while (!customerOrders.isEmpty()) {	System.out.println(customerOrders.poll());}

No código acima, três pedidos de clientes foram criados e adicionados à fila de prioridade.

Quando executamos esse código, obtemos a seguinte saída:

orderId:3, orderAmount:50.0, customerName:customer3orderId:2, orderAmount:300.0, customerName:customer2orderId:1, orderAmount:100.0, customerName:customer1

Como esperado, o resultado vem em ordem decrescente do orderId.

E se quisermos priorizar com base em orderAmount?

Este é novamente um cenário da vida real. Digamos que, por padrão, o objeto CustomerOrder seja priorizado pelo orderId. Mas precisamos de uma maneira pela qual possamos priorizar com base no orderAmount.

Você pode pensar imediatamente que podemos modificar o comparado a função no CustomerOrder cpara encomendar com base em orderAmount.

Mas o CustomerOrder cA moça pode ser usada em vários locais do aplicativo e interferiria com o restante do aplicativo se modificarmos o comparado a função diretamente.

A solução para isso é bastante simples: podemos criar um novo comparador personalizado para a classe CustomerOrder e usá-lo junto com a fila de prioridade

Abaixo está o código para o comparador personalizado:

 static class CustomerOrderComparator implements Comparator {        @Override        public int compare(CustomerOrder o1, CustomerOrder o2)        {            return o1.getOrderAmount() < o2.getOrderAmount() ? 1 : -1;        }    }

Isso é muito semelhante ao comparador inteiro personalizado que vimos anteriormente.

A linha o1.getOrderAmount() < o2.getOrderAmount() ? 1 : -1; indica que precisamos priorizar com base na ordem decrescente de Valor do pedido.

Abaixo está o código que cria a fila de prioridade:

  CustomerOrder c1 = new CustomerOrder(1, 100.0, "customer1");        CustomerOrder c2 = new CustomerOrder(3, 50.0, "customer3");        CustomerOrder c3 = new CustomerOrder(2, 300.0, "customer2");        Queue customerOrders = new PriorityQueue<>(new CustomerOrderComparator());        customerOrders.add(c1);        customerOrders.add(c2);        customerOrders.add(c3);        while (!customerOrders.isEmpty()) {            System.out.println(customerOrders.poll());        }

No código acima, estamos passando o comparador para a fila de prioridade na seguinte linha de código:

Queue customerOrders = new PriorityQueue<>(new CustomerOrderComparator());

Abaixo está o resultado quando executamos este código:

orderId:2, orderAmount:300.0, customerName:customer2orderId:1, orderAmount:100.0, customerName:customer1orderId:3, orderAmount:50.0, customerName:customer3

Podemos ver que os dados vêm em ordem decrescente do orderAmount.

Código

Todo o código discutido neste artigo pode ser encontrado em este repositório GitHub.

Parabéns 😊

Agora você sabe como usar filas prioritárias em Java.

Sobre o autor

Adoro tecnologia e acompanho os avanços no campo. Também gosto de ajudar outras pessoas com meu conhecimento em tecnologia.

Sinta-se à vontade para se conectar comigo na minha conta do LinkedIn https://www.linkedin.com/in/aditya1811/

Você pode também me seguir no Twitter https://twitter.com/adityasridhar18

Sinta-se livre para ler mais dos meus artigos no meu blog em adityasridhar.com.