Query (and the Queryable wrapper) is an alternative to Streams. In other words it is an implementation of Map/Reduce based on the naming style of MS Linq.
Here is an example of filtering a list of numbers for only even numbers, sorted in reverse order:
Integer[] numbers = Range.get(1, 20);
Integer[] evenQueryNumbers = Query.where(numbers, n -> n % 2 == 0).orderBy(OrderBy.Order.Descending, n -> n)
.asArray();
Here is the exact same function but using Java Streams:
Integer[] evenStreamNumbers = Arrays.stream(numbers).filter(n -> n % 2 == 0)
.sorted((o1, o2) -> o2.compareTo(o1)).toArray(Integer[]::new);
Another example using sum() vs. reduce():
String[] names = {"Llewellyn", "Scott"};
int lengthsFromQuery = Query.sum(names, n -> n.length()).intValue();
Here is the exact same function but using Java Streams:
int lengthsFromStream = (int) Arrays.stream(names).map(n -> n.length()).reduce(0, (a, b) -> a + b);
- Simpler interface
- Queryable extends List
- Queryable is customizable
- Uses SQL syntax
Another advantage of Query and Queryable is that Queryable extends List. Here is an example of converting an Array of Integers to Strings:
Using Query:
List<String> strings = Query.select(numbers, n -> "" + n);
Using Streams:
List<String> strings2 = Arrays.stream(numbers).map(n -> "" + n).collect(Collectors.toList());
SelectMany allows you to flatten query results.
For example:
If each element of your SELECT statement is a List you would get back a List<List>. If you would like to flatten that into a List, the easiest way is to do a Query.selectMany().
Because of the limitations of the Java language, we could not override the function to allow you to return either a list or an array in your query. As a workaround we overrode the name, so if you are returning a String[] you would need to call selectManyArray.
The following code extracts the words from the following sentences, and orders them alphabetically:
Queryable<String> names = Queryable.as("Now is the time", "Fourscore and seven years ago",
"When in the course of human events");
Queryable<String> allNames = names.selectMany(n -> Arrays.asList(n.split(" "))).orderBy(n -> n);
resulting in
[0] = Fourscore
[1] = Now
[2] = When
[3] = ago
[4] = and
[5] = course
[6] = events
[7] = human
[8] = in
[9] = is
[10] = of
[11] = seven
[12] = the
[13] = the
[14] = time
[15] = years
Here is a simple example of grouping words by their first letter.
Queryable<String> words = Queryable.as("Jack", "and", "Jill", "jumped", "up", "the", "hill");
Queryable<Entry<Character, Queryable<String>>> result = words.groupBy(w -> w.toLowerCase().charAt(0));
producing:
[0] = j=[Jack, Jill, jumped]
[1] = a=[and]
[2] = u=[up]
[3] = t=[the]
[4] = h=[hill]
In a group by, you can select both how the key is selected and how each object for the key is selected, as well as how the final list is transformed.
Here is an example of doing all three to count the number of words of the same length:
Queryable<String> words = Queryable.as("One Fish Two Fish Red Fish Blue Fish".split(" "));
Queryable<Entry<Object, Object>> result = words.groupBy(w -> w.length(), w -> w.toLowerCase(),
r -> r.join("_"));
resulting in
3 = one_two_red
4 = fish_fish_fish_blue_fish