Firstly, it's better to use an enum as the type of item, instead of String
. In this solution for the sake of simplicity I'll go with strings.
Sidenote: class-names are usually singular nouns. The plural name Items
is justifiable only if an instance of the class is meant to represent multiple domain objects, for example if there would be a field amount
and each instance of Items
represents a zero or more pens, pencils of a particular type.
To define a comparator, you can use Java 8 static methods.
For the first comparison, we need to find out whether an item is a "Pencil" (or not a pen).
Comparator.comparing(items -> items.getIName().equals("Pencil"))
Note that lambda expression produces a boolean
value, and the natural ordering of boolean
values is false
-> true
.
Then we need to chain the second sorting criterion using thenComparing()
.
It can be written either like this, by specifying the type of argument:
Comparator.comparing((Items items) -> items.getIName().equals("Pencil"))
.thenComparing(Items::getIPrice)
Or by using so-called type witness:
Comparator.<Items, Boolean>comparing(items -> items.getIName().equals("Pencil"))
.thenComparing(Items::getIPrice)
In case if we would not provide the generic type parameter explicitly, compiler would treat the objects consumed by the comparing()
and thenComparing()
as being of Object
and it would be impossible to invoke methods getIName()
and getIPrice()
.
It would happen because lambda expressions and method references, are so-called poly expressions, they are sensitive to the context in which they appear. And based on the context, compiler should infer their types. In this case, when we're chaining the methods, it becomes impossible to infer the type of each lambda and reference based solely on the resulting type of the comparator.
So, that how you can declare a BlockingQueue
:
BlockingQueue<Items> queue = new PriorityBlockingQueue<>(10,
Comparator.comparing((Items items) -> items.getIName().equals("Pencil"))
.thenComparing(Items::getIPrice)
);
A link to Online Demo