CARVIEW |
Underscore-java
Underscore-java is a port of Underscore.js
for Java. It is a utility-belt library that provides a lot of the
functional programming support that you would expect in Prototype.js
(or Ruby).
Underscore-java provides dozens of functions that
support both the usual functional suspects: map, select, invoke - as
well as more specialized helpers: function binding, sorting, deep
equality testing, and so on. It delegates to built-in functions where
applicable.
Underscore-java is compatible with Java 11 and later.
The project is hosted on GitHub. Contributions are welcome.
Download
Collection Functions (Arrays, Structs, Queries, or Objects)
each U.each(collection, iterator)
Iterates
over a collection of elements, yielding
each in turn to an iterator
function. The iterator is bound to the context
object (component or
struct), if one is passed. Each invocation of iterator is
called with
argument: (element).
U.each(asList(1, 2, 3), item -> System.out.print(item + ",")); // 1,2,3, Live example final int[] index = {0}; U.each(asList(1, 2, 3), item -> { System.out.print(index[0] + "=" + (item * multiplier) + ","); index[0] += 1; }); // 0=2,1=4,2=6, Live example
map U.map(collection, iterator)
Produces
a new array of values by mapping each
value in collection through a
transformation function (iterator).
U.map(asList(1, 2, 3), item -> item * 3); // [3, 6, 9] Live example U.map(new LinkedHashMap<Integer, String>() {{ put(1, "one"); put(2, "two"); put(3, "three"); }} .entrySet(), item -> item.getKey() * 3); // [3, 6, 9] Live example
reduce U.reduce(collection, iterator,
memo)
Also
known as inject and foldl, reduce boils
down a collection of values
into a single value. Memo is the initial state of
the reduction, and
each successive step of it should be returned by
iterator.
U.reduce(asList(1, 2, 3), (item1, item2) -> item1 + item2, 0 ); // 6
reduceRight U.reduceRight(collection, iterator,
memo)
U.reduceRight(asList(asList(0, 1), asList(2, 3), asList(4, 5)), (BiFunction<List<Integer>, List<Integer>, List<Integer>>) (item1, item2) -> { List<Integer> list = new ArrayList<>(item1); list.addAll(item2); return list; }, Collections.emptyList() ); // [4, 5, 2, 3, 0, 1]
find U.find(collection,
iterator)
Looks
through each value in the collection, returning
the first one that
passes a truth test (iterator). The function returns as
soon as it finds
an acceptable element, and doesn't traverse the entire
collection.
U.find(asList(1, 2, 3, 4, 5, 6), item -> item % 2 == 0).get(); // 2
filter U.filter(collection, iterator)
Looks through each value in the collection,
returning an array of all the values that pass a truth test
(iterator).
U.filter(asList(1, 2, 3, 4, 5, 6), item -> item % 2 == 0); // [2, 4, 6]
where U.where(list, properties)
Looks
through each value in the list, returning an array of all
the values
that contain all of the key-value pairs listed in
properties.
class Book { public final String title; public final String author; public final Integer year; public Book(final String title, final String author, final Integer year) { this.title = title; this.author = author; this.year = year; } public String toString() { return "title: " + title + ", author: " + author + ", year: " + year; } } List<Book> listOfPlays = new ArrayList<Book>() { { add(new Book("Cymbeline2", "Shakespeare", 1614)); add(new Book("Cymbeline", "Shakespeare", 1611)); add(new Book("The Tempest", "Shakespeare", 1611)); } }; U.where(listOfPlays, asList( Map.<String, Object>entry("author", "Shakespeare"), Map.<String, Object>entry("year", Integer.valueOf(1611)))); // [title: Cymbeline, author: Shakespeare, year: 1611, title: The Tempest, author: Shakespeare, year: 1611]
findWhere U.findWhere(collection, properties)
Looks through the collection and returns the first
value that matches all of the key-value pairs listed in
properties.
class Book { public final String title; public final String author; public final Integer year; public Book(final String title, final String author, final Integer year) { this.title = title; this.author = author; this.year = year; } public String toString() { return "title: " + title + ", author: " + author + ", year: " + year; } } List<Book> listOfPlays = new ArrayList<Book>() { { add(new Book("Cymbeline2", "Shakespeare", 1614)); add(new Book("Cymbeline", "Shakespeare", 1611)); add(new Book("The Tempest", "Shakespeare", 1611)); } }; U.findWhere(listOfPlays, asList( Map.<String, Object>entry("author", "Shakespeare"), Map.<String, Object>entry("year", Integer.valueOf(1611)))).get(); // "title: Cymbeline, author: Shakespeare, year: 1611"
reject U.reject(collection, iterator)
Returns the values in collection without the
elements that the truth test (iterator) passes. The opposite of
filter.
U.reject(asList(1, 2, 3, 4), item -> item % 2 == 0); // [1, 3]
all U.all(collection, iterator)
Returns true if all of the values in the
collection pass the iterator truth test.
U.all(asList(1, 2, 3, 4), item -> item % 2 == 0); // false U.all(asList(1, 2, 3, 4), item -> item < 5); // true
any U.any(collection, iterator)
Returns
true if any of the values in the collection pass the iterator truth
test. Short-circuits and stops traversing the collection if a true
element is found.
U.any(asList(1, 2, 3, 4), item -> item % 2 == 0); // true U.any(asList(1, 2, 3, 4), item -> item == 5); // false
include U.include(collection, value)
Returns true if the value is present in the
collection.
U.include(asList(1, 2, 3), 3); // true
invoke U.invoke(collection,
methodName, [arguments])
Calls
the method named by methodName
on each value in the collection. The
arguments struct passed to invoke will be
forwarded on to the method
invocation.
U.invoke(asList(" foo", " bar "), "trim"); // ["foo", "bar"]
pluck U.pluck(collection,
propertyName)
A convenient version of what is perhaps the most
common use-case for map: extracting a collection of property
values.
class Person { public final String name; public final Integer age; public Person(final String name, final Integer age) { this.name = name; this.age = age; } }; U.pluck(asList(new Person("moe", 40), new Person("larry", 50), new Person("curly", 40)), "name"); // ["moe", "larry", "curly"]
max U.max(collection, [iterator])
Returns
the maximum value in collection. If iterator
is passed, it will be used
on each value to generate the criterion by which the
value is ranked.
U.max(asList(10, 5, 100, 2, 1000)); // 1000 U.max(asList(10, 5, 100, 2, 1000), item -> -item); // 2
min U.min(collection, [iterator])
Returns
the minimum value in collection. If
iterator is passed, it will be used
on each value to generate the criterion
by which the value is ranked.
U.min(asList(10, 5, 100, 2, 1000)); // 2 U.min(asList(10, 5, 100, 2, 1000), item -> -item); // 1000
sortBy U.sortBy(collection,
iterator)
Returns
a sorted copy of collection,
ranked in ascending order by the results
of running each value through
iterator. Iterator may also be the string
name of the object key to sort by.
U.sortBy(asList(1, 2, 3, 4, 5, 6), item -> Double.valueOf(Math.sin(item) * 1000).intValue());
=> [5, 4, 6, 3, 1, 2]
groupBy U.groupBy(collection,
iterator)
Splits
a collection into sets, grouped by the
result of running each value
through iterator. If iterator is a string instead
of a function, groups
by the property named by iterator on each of the
values.
U.groupBy(asList(1.3, 2.1, 2.4), , Math::floor);
=> {1.0=[1.3], 2.0=[2.1, 2.4]}
countBy U.countBy(collection,
iterator)
Sorts
a collection into groups and returns a count
for the number of objects
in each group. Similar to groupBy, but instead of
returning a list of
values, returns a count for the number of values in that
group.
class Person { public final String name; public final Integer age; public Person(final String name, final Integer age) { this.name = name; this.age = age; } public String toString() { return name + ", " + age; } } final Map<String, Integer> result = U.countBy(asList(new Person("moe", 40), new Person("moe", 50), new Person("curly", 60)), person -> person.name);
=> {moe=2, curly=1}
sortedIndex
U.sortedIndex(collection, value, [iterator])
Uses
a
binary search to determine the index at which the value should be
inserted into
the collection in order to maintain the collection's
sorted order. If an
iterator is passed, it will be used to compute the
sort ranking of each
value.
U.sortedIndex(asList(10, 20, 30, 40, 50), 35);
=> 3
shuffle U.shuffle(array)
Returns a shuffled copy of the array, using a version of the
Fisher-Yates shuffle.
U.shuffle(asList(1, 2, 3, 4, 5, 6)
=> [4, 1, 6, 3, 5, 2]
sample U.sample(list, [n])
Produce a random sample from the list. Pass a number to
return n random elements from the list. Otherwise a single random
item will be returned.
U.sample(asList(1, 2, 3, 4, 5, 6)
=> 4 U.sample(asList(1, 2, 3, 4, 5, 6), 3)
=> [1, 6, 2]
toArray U.toArray(collection)
Converts the collection (object), into an array.
U.<Integer>toArray(asList(1, 2, 3, 4));
=> [1, 2, 3, 4]
toMap U.toMap(collection)
Converts
the collection to a map object.
U.toMap((new LinkedHashMap<String, String>() { { put("name1", "one"); put("name2", "two"); } }).entrySet());
=> {name1=one, name2=two}
size U.size(collection)
Return the number of values in the collection.
U.size(asList(1, 2, 3, 4));
=> 4
Array Functions
first U.first(array, [n])
Returns the first element of an array. Passing n will return the
first n elements of the array.
U.first(asList(5, 4, 3, 2, 1)); => 5
initial U.initial(array, [n])
Returns
everything but the last entry of the array. Especially
useful on the
arguments object. Pass n to exclude the last n elements from the
result.
U.initial(asList(5, 4, 3, 2, 1));
=> [5, 4, 3, 2]
last U.last(array, [n])
Returns the last element of an array. Passing n will return the
last n elements of the array.
U.last(asList(5, 4, 3, 2, 1));
=> 1
rest U.rest(array, [index])
Returns the rest of the elements in an array. Pass an index to
return the values of the array from that index onward.
U.rest(asList(5, 4, 3, 2, 1));
=> [4, 3, 2, 1]
compact U.compact(array)
Returns a copy of the array with all falsy values removed. In
Coldfusion, false, 0, and "" are all falsy.
U.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]
flatten U.flatten(array, [shallow])
Flattens a nested array (the nesting can be to any depth). If
you pass shallow, the array will only be flattened a single
level.
U.flatten(asList(1, asList(2, asList(3, asList(asList(4)))))); => [1, 2, 3, 4];
U.flatten(asList(1, asList(2, asList(3, asList(asList(4))))), true); => [1, 2, [3, [[4]]]];
without U.without(array, [values])
Returns a copy of the array with all instances of the values
removed.
U.without(asList(1, 2, 1, 0, 3, 1, 4), 0, 1) => [2, 3, 4]
union U.union(*arrays)
Computes
the union of the passed-in arrays: the collection of
unique items, in
order, that are present in one or more of the
arrays.
U.union(asList(1, 2, 3), asList(101, 2, 1, 10), asList(2, 1)); => [1, 2, 3, 101, 10]
intersection
U.intersection(*arrays)
Computes
the collection of
values that are the intersection of all the arrays.
Each value in the result is
present in each of the arrays.
U.intersection(asList(1, 2, 3), asList(101, 2, 1, 10), asList(2, 1));
=> [1, 2]
difference U.difference(array, others)
Similar to without, but returns the values from array
that are not present in the other arrays.
U.difference(asList(1, 2, 3, 4, 5), asList(5, 2, 10));
=> [1, 3, 4]
uniq U.uniq(array, [iterator])
Produces
a duplicate-free version of the array.
If you want to compute unique items based on a
transformation, pass an iterator function.
U.uniq(asList(1, 2, 1, 3, 1, 4));
=> [1, 2, 3, 4]
zip U.zip(*arrays)
Merges
together the values of each of the arrays with the
values at the
corresponding position. Useful when you have separate data
sources that
are coordinated through matching array
indexes.
U.zip(asList("moe", "larry", "curly"), asList("30", "40", "50"), asList("true", "false", "false")); => [[moe, 30, true], [larry, 40, false], [curly, 50, false]]
object U.object(array, [values])
Converts an array into a struct. Pass either a single array
of [key, value] pairs, or an array of keys, and an array of
values.
U.object(asList("moe", "larry", "curly"), asList("30", "40", "50")); => [(moe, 30), (larry, 40), (curly, 50)]
indexOf
U.indexOf(array, value)
Returns
the index at which value can
be found in the array, or -1 if value is
not present in the array.
U.indexOf(asList(1, 2, 3), 2);
=> 1
lastIndexOf U.lastIndexOf(array, value)
Returns the index of the last occurrence of value in
the array, or -1 if value is not present.
U.lastIndexOf(asList(1, 2, 3, 1, 2, 3), 2);
=> 4
range U.range([start], stop, [step])
A
function to create flexibly-numbered arrays of integers,
handy for each
and map loops. start, if omitted, defaults to 0; step defaults
to 1.
Returns an array of integers from start to stop, incremented (or
decremented) by step, exclusive.
U.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
U.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
U.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
U.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
U.range(0);
=> []
concat U.concat(*arrays)
Concatenates any number of arrays together an returns the
result.
U.concat(asList(1, 2), asList(3, 4))
=> [1, 2, 3, 4];
reverse U.reverse(array)
Returns a copy of the array in reverse
order.
U.reverse(asList(1, 2, 3))
=> [3, 2, 1]
join U.join(array, [separator])
Returns a string with all array elements joined together.
Default separator is a single space.
U.join(asList(1, 2), " and "); => "1 and 2"
slice U.slice(array, [from], [to])
Returns a subsection of the array. Negative values for to and
from offset from the end of the array.
U.slice(asList(1, 2, 3, 4), 1);
=> [2, 3, 4]
U.slice(asList(1, 2, 3, 4), 3);
=> [3, 4]
U.slice(asList(1, 2, 3, 4), 2, -1);
=> [2, 3]
U.slice(asList(1, 2, 3, 4), -3, -1);
=> [2, 3]
Functions
bind U.bind(function, object, [*arguments])
Bind
a function to a structure, meaning that
whenever the function is
called, the value of "this" will be the structure.
Optionally, bind
arguments to the function to pre-fill them, also known as
partial
application.
class GreetingFunction implements Function<String, String> { private final String name; public GreetingFunction(final String name) { this.name = name; } public String apply(final String greeting) { return greeting + ": " + this.name; } } U.bind(new GreetingFunction("moe")).apply("hi"); => "hi: moe"
memoize
U.memoize(function)
Memoizes
a given function by caching the
computed result. Useful for speeding up
slow-running computations.
class FibonacciFuncion1 extends MemoizeFunction<Integer> { public Integer calc(final Integer n) { return n < 2 ? n : apply(n - 1) + apply(n - 2); } } fibonacci = new FibonacciFuncion1().apply(10)); // 55
delay
U.delay(function, wait, arguments)
Delays a function for the given number of
milliseconds, and then calls it with the arguments supplied in the args
struct.
U.delay(new Supplier<String>() { public String get() { return "hi"; } }, 1000); => "hi" // appears after one second
once U.once(function)
Returns a function that will be executed at most one time, no
matter how often you call it. Useful for lazy initialization.
final Integer[] counter = new Integer[] {0}; Supplier<Integer> incr = new Supplier<Integer>() { public Integer get() { counter[0]++; return counter[0]; } }; Supplier<Integer> onceIncr = U.once(incr); onceIncr.get(); onceIncr.get(); => counter[0] == 1
debounce
U.debounce(function, wait)
Returns
a function that, as long as it
continues to be invoked, will not be
triggered. The function will be called
after it stops being called for N
milliseconds.
final Integer[] counter = new Integer[] {0}; Supplier<Void> incr = new Supplier<Void>() { public Void get() { counter[0]++; return null; } }; Supplier<Void> debouncedIncr = U.debounce(incr, 50); debouncedIncr.get(); debouncedIncr.get(); U.delay(debouncedIncr, 16); U.delay(new Supplier<Void>() { public Void get() { System.out.println(counter[0]); return null; } }, 60); Thread.sleep(120); => function argument is called only once
after
U.after(count, function)
Returns
a function that will only be executed after being called
N times. When
count <= 0, the result of calling the function immediately is
returned.
final List<Integer> notes = asList(1, 2, 3); final Supplier<Integer> renderNotes = U.after(notes.size(), new Supplier<Integer>() { public Integer get() { return 4; } }); final List<Integer> result = new ArrayList<Integer>(); U.<Integer>each(notes, new Consumer<Integer>() { public void accept(Integer item) { result.add(item); Integer afterResult = renderNotes.get(); if (afterResult != null) { result.add(afterResult); } } }); => [1, 2, 3, 4]
before
U.before(count, function)
Returns
a function that will only be executed after being called
N times. When
count <= 0, the result of calling the function immediately is
returned.
final List<Integer> notes = asList(1, 2, 3); final Supplier<Integer> renderNotes = U.before(notes.size() - 1, new Supplier<Integer>() { public Integer get() { return 4; } }); final List<Integer> result = new ArrayList<Integer>(); U.<Integer>each(notes, new Consumer<Integer>() { public void accept(Integer item) { result.add(item); Integer afterResult = renderNotes.get(); if (afterResult != null) { result.add(afterResult); } } }); => [1, 4, 2, 4, 3, 4]
wrap U.wrap(function, wrapper)
Returns
the first function passed as an argument to the
second, allowing you to
adjust arguments, run code before and after, and
conditionally execute
the original function.
Function<String, String> hello = new Function<String, String>() { public String apply(final String name) { return "hello: " + name; } }; Function<Void, String> result = U.wrap(hello, new Function<Function<String, String>, String>() { public String apply(final Function<String, String> func) { return "before, " + func.apply("moe") + ", after"; } }); result.apply(null); => "before, hello: moe, after"
compose U.compose(*functions)
Returns
a function that is the composition of a list of
functions, each
function consumes the return value of the function that
follows. In math
terms, composing the functions f(), g(), and h() produces
f(g(h())).
Function<String, String> greet = new Function<String, String>() { public String apply(final String name) { return "hi: " + name; } }; Function<String, String> exclaim = new Function<String, String>() { public String apply(final String statement) { return statement.toUpperCase() + "!"; } }; Function<String, String> welcome = U.compose(greet, exclaim); welcome.apply("moe"); => 'hi: MOE!';
Object/Struct Functions
keys U.keys(object)
Retrieve all the names of the object's
properties.
U.keys(new LinkedHashMap<String, Object>() { { put("one", 1); put("two", 2); put("three", 3); } }); => ["one", "two", "three"]
values U.values(object)
Return all of the values of the object's own properties.
U.values(new LinkedHashMap<String, Integer>() { { put("one", 1); put("two", 2); put("three", 3); } }); => [1, 2, 3]
pairs U.pairs(object)
Convert
an object into a list of [key, value] pairs.
U.pairs(new LinkedHashMap<String, Integer>() { { put("one", 1); put("two", 2); put("three", 3); } }); => [(one, 1), (two, 2), (three, 3)]
invert
U.invert(object)
Returns
a copy of the object where the keys have become the
values and the
values the keys. For this to work, all of your object's values
should be
unique and string serializable.
U.invert(new LinkedHashMap<String, String>() { { put("Moe", "Moses"); put("Larry", "Louis"); put("Curly", "Jerome"); } }); => [(Moses, Moe), (Louis, Larry), (Jerome, Curly)]
functions U.functions(object)
Returns
a sorted array of the names of every method in an
object -- that is to
say, the name of every function property of the
object.
U.functions(U.class); => ["all", "any", "bind", "clone", "compact", "compose" ...
extend
U.extend(destination, *sources)
Copy
all of the properties in the source objects over
to the destination
object, and return the destination object. It's in-order, so
the last
source will override properties of the same name in previous
arguments.
U.extend(new LinkedHashMap<String, Object>() { { put("name", "moe"); } }, new LinkedHashMap<String, Object>() { { put("age", 50); } }); => {name=moe, age=50}
pick
U.pick(object, *keys)
Return a copy of the object, filtered to only have values for
the whitelisted keys (or array of valid keys).
U.pick( new LinkedHashMap<String, Object>() { { put("name", "moe"); put("age", 50); put("userid", "moe1"); } }, "name", "age" );
=> [(name, moe), (age, 50)]
omit U.omit(object, *keys)
Return a copy of the object, filtered to omit the blacklisted
keys (or array of keys).
U.omit( new LinkedHashMap<String, Object>() { { put("name", "moe"); put("age", 50); put("userid", "moe1"); } }, "userid" );
=> [(name, moe), (age, 50)]
defaults U.defaults(object, *defaults)
Fill
in missing properties in object with default
values from the defaults
objects, and return the object. As soon as the
property is filled,
further defaults will have no effect.
Map<String, String> iceCream = new LinkedHashMap<String, String>() { { put("flavor", "chocolate"); } }; Map<String, String> result = U.defaults(iceCream, new LinkedHashMap<String, String>() { { put("flavor", "vanilla"); put("sprinkles", "lots"); } }); => {flavor=chocolate, sprinkles=lots}
clone U.clone(object)
Create a shallow-copied clone of the object. Any nested structs or
objects will be copied by reference, not duplicated.
U.clone(new LinkedHashMap<String, String>() { { put("name", "moe"); } });
=> {name=moe}
has U.has(object, key)
Does the object contain the given key?
U.has(new LinkedHashMap<String, Integer>() { { put("a", 1); put("b", 2); put("c", 3); } }, "b"); => true
isEqual U.isEqual(object, other)
Performs a deep comparison between the two objects, to
determine if they should be considered equal.
Map<String, Object> stooge = new LinkedHashMap<String, Object>() { { put("name", "moe"); put("luckyNumbers", asList(13, 27, 34)); } }; Map<String, Object> clone = new LinkedHashMap<String, Object>() { { put("name", "moe"); put("luckyNumbers", asList(13, 27, 34)); } }; => stooge == clone // false => U.isEqual(stooge, clone); // true
isEmpty U.isEmpty(object)
Returns true if object contains no values.
U.isEmpty(asList(1, 2, 3, 4))
=> false
U.isEmpty(new ArrayList<String>())
=> true
isArray U.isArray(object)
Returns true if object is an Array.
U.isArray("string")
=> false
U.isArray(new int[] {1, 2, 3, 4, 5});
=> true
isObject U.isObject(object)
Returns true if value is an Object.
U.isObject(new LinkedHashMap<String, String>())
=> true
U.isObject(null);
=> false
isFunction U.isFunction(object)
Returns true if object is a Function.
U.isFunction(new Function<String, Integer>() { public Integer apply(final String arg) { return null; } }) => true
isString U.isString(object)
Returns true if object is a String. Uses Java String type
comparison.
U.isString("moe");
=> true
U.isString(1);
=> false
isNumber U.isNumber(object)
Returns true if object is of a Java numeric
type.
U.isNumber(1);
=> true
isBoolean U.isBoolean(object)
Returns true if object is a boolean.
U.isBoolean(false);
=> true
isDate U.isDate(object)
Returns true if object is a date.
U.isDate(new java.util.Date())
=> true
Utility Functions
times U.times(n, iterator)
Invokes the given iterator function n
times.
final List<Integer> result = new ArrayList<Integer>(); U.times(3, new Supplier<Integer>() { public Integer get() { result.add(1); return null; } }); => [1, 1, 1]
random U.random([min], max)
Returns
a random integer between min and max, inclusive. If
you only pass one
argument, it will return a number between 0 and that number.
U.random(0, 100); => 42
mixin U.mixin(object)
Allows
you to extend Underscore with your own utility functions.
U.mixin("capitalize", new Function<String, String>() { public String apply(final String string) { return String.valueOf(string.charAt(0)).toUpperCase() + string.substring(1).toLowerCase(); } }); new U("fabio").call("capitalize").get() => "Fabio"
uniqueId U.uniqueId(prefix)
Generates an identifier that is unique for this instance of
Underscore
U.uniqueId("c");
=> c1
uniquePassword U.uniquePassword()
Generates a random text with 8-15 characters length
U.uniquePassword();
=> FKV276qgb-&
escape U.escape(input)
Escapes a string for insertion into HTML, replacing &,
<, >, and " characters.
U.escape("Curly, Larry & Moe"); => "Curly, Larry & Moe"
result U.result(object, property)
If the value of the named property is a function then invoke it;
otherwise, return it.
Map<String, Object> object = new LinkedHashMap<String, Object>() { { put("cheese", "crumpets"); put("stuff", new Supplier<String>() { public String get() { return "nonsense"; } }); } }; U.result(object.entrySet(), new Predicate<Map.Entry<String, Object>>() { public boolean test(Map.Entry<String, Object> item) { return item.getKey().equals("cheese"); } }); => "crumpets"
U.result(object.entrySet(), new Predicate<Map.Entry<String, Object>>() { public boolean test(Map.Entry<String, Object> item) { return item.getKey().equals("stuff"); } }); => "nonsense"
Chaining
You can use Underscore-java in either an object-oriented or a functional style, depending on your preference. The following two lines of code are identical ways to double a list of numbers.
U.map(asList(1, 2, 3), new Function<Integer, Integer>() { public Integer apply(Integer item) { return item * 2; } }); new U<Integer>(asList(1, 2, 3)).map(new Function<Integer, Integer>() { public Integer apply(Integer item) { return item * 2; } });
Calling chain will cause all future method calls to return wrapped objects. When you've finished the computation, call item or value to retrieve the final value. Here's an example of chaining together a map/flatten/reduce, in order to get the word count of every word in a song.
final List<Map<String, Object>> lyrics = new ArrayList<Map<String, Object>>() { { add(new LinkedHashMap<String, Object>() { { put("line", 1); put("words", "I'm a lumberjack and I'm okay"); } }); add(new LinkedHashMap<String, Object>() { { put("line", 2); put("words", "I sleep all night and I work all day"); } }); add(new LinkedHashMap<String, Object>() { { put("line", 3); put("words", "He's a lumberjack and he's okay"); } }); add(new LinkedHashMap<String, Object>() { { put("line", 4); put("words", "He sleeps all night and he works all day"); } }); } }; final String result = U.chain(lyrics) .map( new Function<Map<String, Object>, List<String>>() { public List<String> apply(Map<String, Object> item) { return asList(String.valueOf(item.get("words")).split(" ")); } }) .flatten() .reduce( new BiFunction<Map<String, Integer>, String, Map<String, Integer>>() { public Map<String, Integer> apply(Map<String, Integer> accum, String item) { if (accum.get(item) == null) { accum.put(item, 1); } else { accum.put(item, accum.get(item) + 1); } return accum; } }, new LinkedHashMap<String, Integer>() ) .item(); => {lumberjack: 2, all: 4, night: 2 ... }
chainU.chain(obj)
Returns a wrapped object. Calling methods on this object will continue
to return wrapped objects until item or value is called.
final List<Map<String, Object>> stooges = new ArrayList<Map<String, Object>>() { { add(new LinkedHashMap<String, Object>() { { put("name", "curly"); put("age", 25); } }); add(new LinkedHashMap<String, Object>() { { put("name", "moe"); put("age", 21); } }); add(new LinkedHashMap<String, Object>() { { put("name", "larry"); put("age", 23); } }); } }; final String youngest = U.chain(stooges) .sortBy( new Function<Map<String, Object>, Integer>() { public Integer apply(Map<String, Object> item) { return (Integer) item.get("age"); } }) .map( new Function<Map<String, Object>, String>() { public String apply(Map<String, Object> item) { return item.get("name") + " is " + item.get("age"); } }) .first().item(); => "moe is 21"
valueU.chain(obj).value()
Extracts the value of a wrapped object.
U.chain(Arrays.asList(1, 2, 3)).value(); => [1, 2, 3]
Change Log
1.116 --
August 1st, 2025
- Bump org.junit.jupiter:junit-jupiter-api from 5.13.2 to 5.13.3
- Bump org.junit.platform:junit-platform-launcher from 1.13.2 to 1.13.3
- Bump org.junit.jupiter:junit-jupiter-engine from 5.13.2 to 5.13.3
- Removed codebeat badge
- Bump org.junit.jupiter:junit-jupiter-engine from 5.13.3 to 5.13.4
- Bump org.junit.jupiter:junit-jupiter-api from 5.13.3 to 5.13.4
- Bump org.junit.platform:junit-platform-launcher from 1.13.3 to 1.13.4
- Added method U.jsonFolderToXml(jsonFolder, xmlFolder, identStep)
- Resolved Idea warnings
1.115 --
July 1st, 2025
- Jdk 25
- Spring-boot 3.5.3
- Updated pom-central.xml
- Updated JUnit dependencies
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.9.3.0 to 4.9.3.2
1.114 --
June 1st, 2025
- Spring-boot 3.4.5
- Added method U.fileXmlToJson(xmlFileName, jsonFileName, identStep)
- Added method U.streamXmlToJson(xmlInputStream, jsonOutputStream, identStep)
- Improved sources
- Added method U.fileJsonToXml(jsonFileName, xmlFileName, identStep)
- Added method U.streamJsonToXml(jsonInputStream, xmlOutputStream, identStep)
- Add securityscorecards badge
1.113 --
May 1st, 2025
- Bump org.jacoco:jacoco-maven-plugin from 0.8.12 to 0.8.13
- Resolved Idea warnings
- Fixed SonarQube warnings
1.112 --
April 1st, 2025
- Updated libraries
- Bump org.apache.maven.plugins:maven-project-info-reports-plugin from 3.8.0 to 3.9.0
- Improved defer test
- JDK 24 Added to CI Configuration
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.9.1.0 to 4.9.2.0
- Added methods U.mergeXmlsOrJsonsToJson(xmlsOrJsons) and U.mergeXmlsOrJsonsToXml(xmlsOrJsons)
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.9.2.0 to 4.9.3.0
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.5.2 to 3.5.3
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.5.2 to 3.5.3
1.111 --
March 1st, 2025
- Created scorecard.yml
- Updated LICENSE
- Improved source format
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.6.6 to 4.9.1.0
- Spring boot 3.4.3
- Updated copyright headers to 2025
- Bump org.apache.maven.plugins:maven-compiler-plugin from 3.13.0 to 3.14.0
- Added examples to the README for U.xmlToJsonMinimum(xml, step) and U.jsonToXmlMinimum(json, step)
- Enhanced the XmlBuilder example
- Update Codebeat badge
1.110 --
February 1st, 2025
- Fixed Sonar warnings
1.109 --
January 1st, 2025
- Improved attribute parser to handle values with equal signs
- Fixed sonar warnings
- Spring boot 3.4.1
- Fixed Sonar warning
1.108 --
December 1st, 2024
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.5.1 to 3.5.2
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.5.1 to 3.5.2
- Updated junit
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.6.5 to 4.8.6.6
- Updated maven.yml
- Spring boot 3.4.0
1.107 --
November 1st, 2024
- Bump org.apache.maven.plugins:maven-checkstyle-plugin from 2.17 to 3.0.0
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.5.0 to 3.5.1
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.5.0 to 3.5.1
- Removed PMD report plugin from the build configuration
- Added method U.jsonToXmlMinimum(json, step)
- Updated azure-pipelines.yml
- Bump org.codehaus.mojo:taglist-maven-plugin from 3.1.0 to 3.2.1
- Spring boot 3.3.5
- Changed semaphore badge
- Bump org.apache.maven.plugins:maven-project-info-reports-plugin from 3.7.0 to 3.8.0
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.6.4 to 4.8.6.5
- Bump org.apache.maven.plugins:maven-site-plugin from 3.20.0 to 3.21.0
- Bump org.apache.maven.plugins:maven-jxr-plugin from 3.5.0 to 3.6.0
- Fixed SonarCloud warnings
1.106 --
October 1st, 2024
- Bump org.apache.maven.plugins:maven-pmd-plugin from 3.24.0 to 3.25.0
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.4.0 to 3.5.0
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.4.0 to 3.5.0
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.6.2 to 4.8.6.3
- Spring boot 3.3.3
- Updated dependencies
- Added Java 23 support for CI pipeline
- Spring boot 3.3.4
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.6.3 to 4.8.6.4
1.105 --
September 1st, 2024
- Renamed the method for compacting the list
- Added method U.xmlToJsonMinimum(xml)
- Fixed Idea warnings
- Fixed SonarCloud warnings
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.3.1 to 3.4.0
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.3.1 to 3.4.0
- Bump org.apache.maven.plugins:maven-site-plugin from 3.12.1 to 3.20.0
- Bump org.apache.maven.plugins:maven-jxr-plugin from 3.4.0 to 3.5.0
- Bump org.apache.maven.plugins:maven-project-info-reports-plugin from 3.6.2 to 3.7.0
- Added the logo image for the library
1.104 --
August 1st, 2024
- Bump org.codehaus.mojo:taglist-maven-plugin from 3.0.0 to 3.1.0
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.6.1 to 4.8.6.2
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.3.0 to 3.3.1
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.3.0 to 3.3.1
- Bump org.apache.maven.plugins:maven-project-info-reports-plugin from 3.6.1 to 3.6.2
- Bump org.apache.maven.plugins:maven-pmd-plugin from 3.23.0 to 3.24.0
- Spring boot 3.3.2
1.103 --
July 1st, 2024
- Bump org.apache.maven.plugins:maven-jxr-plugin from 3.3.2 to 3.4.0
- Bump org.apache.maven.plugins:maven-pmd-plugin from 3.22.0 to 3.23.0
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.2.5 to 3.3.0
- Bump org.apache.maven.plugins:maven-project-info-reports-plugin from 3.5.0 to 3.6.0
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.5 to 3.3.0
- Bump org.apache.maven.plugins:maven-jar-plugin from 3.4.0 to 3.4.2
1.102 --
June 1st, 2024
- Implemented the U.joinToString() method
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.4.0 to 4.8.5.0
- Resolved Idea warnings
- Refactored the Base32 class
- Spring boot 3.2.5
1.101 --
May 1st, 2024
- Updated azure-pipelines.yml
- Bump org.jacoco:jacoco-maven-plugin from 0.8.11 to 0.8.12
- Improved Json class
- Resolved duplicate entries within the Json class
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.3.1 to 4.8.4.0
- Bump org.apache.maven.plugins:maven-jar-plugin from 3.3.0 to 3.4.0
- Bump org.apache.maven.plugins:maven-pmd-plugin from 3.21.2 to 3.22
1.100 --
April 1st, 2024
- Updated codeql.yml
- Updated scorecard.yml
- Fixed idea warnings for class Xml
- Fixed idea warnings for class Json
- Bump org.apache.maven.plugins:maven-compiler-plugin from 3.12.1 to 3.13.0
- Included Java 22 for continuous integration
1.99 --
March 1st, 2024
- Corrected UTF-8 character
- Added new mode XmlToJsonMode.REPLACE_MINUS_WITH_AT
- Added new mode XmlToJsonMode.REPLACE_EMPTY_TAG_WITH_NULL_AND_MINUS_WITH_AT
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.3.0 to 4.8.3.1
- Upgraded to JUnit 5.10.2
- Created codeql.yml
- Enhanced parsing of XML attributes
- spring-web was updated to version 6.1.4
1.98 --
February 1st, 2024
- Bump org.apache.maven.plugins:maven-jxr-plugin from 3.3.1 to 3.3.2
- Updated copyright headers to 2024
- Enhanced source formatting
- Bump org.apache.maven.plugins:maven-surefire-report-plugin from 3.2.2 to 3.2.5
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.3 to 3.2.5
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.8.2.0 to 4.8.3.0
- Updated Spring Boot to version 3.2.2
1.97 --
January 1st, 2024
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.2 to 3.2.3
- Bump org.apache.maven.plugins:maven-compiler-plugin
- Excluded Java versions 19 and 20 from continuous integration
- Bump org.apache.maven.plugins:maven-jxr-plugin from 3.3.1 to 3.3.2
1.96 --
December 1st, 2023
- Bump org.apache.maven.plugins:maven-pmd-plugin from 3.21.0 to 3.21.2
- Bump org.apache.maven.plugins:maven-surefire-plugin from 3.1.2 to 3.2.2
- Bump com.github.spotbugs:spotbugs-maven-plugin from 4.7.3.6 to 4.8.1.0
1.95 --
November 1st, 2023
- Improved creation of ArrayList and LinkedHashMap
- Added methods U.propertiesToMap(properties) and U.mapToProperties(map)
1.94 --
October 1st, 2023
- Enhanced GitHub workflows and included Java 21
- Added U.associateBy(iterable, func)
1.93 --
September 1st, 2023
- Substituted the customized Optional with java.util.Optional
- Updated junit
- Improved json parser tests
1.92 --
August 1st, 2023
- The interfaces have been relocated within the Underscore class
- XML attribute parser has been enhanced
1.91 --
July 2nd, 2023
- Improved Optional
- Removed methods Underscore.topNCompetitors() and Underscore.minimumDays()
- Updated appveyor.yml
1.90 --
June 1st, 2023
- Improved maven plugins
- Removed Json.Type.JAVA
- Optimized json generation
- Improved JSON serialization
1.89 --
May 1st, 2023
- Improved U.fetch() and U.downloadUrl()
- Added com.github.underscore.XmlBuilder
1.88 --
April 1st, 2023
- Updated maven dependencies
- Fixed Idea warnings
1.87 --
March 1st, 2023
- Replaced class Tuple with Map.Entry
- Removed class Trie and methods U.gcd(), U.findGcd()
- Fixed pack configuration
1.86 --
February 1st, 2023
- Improved modes for U.xmlToJson() and U.jsonToXml() methods
- Added methods U.xmlOrJsonToXml() and U.xmlOrJsonToJson()
1.85 --
January 2nd, 2023
- Added method U.fromXmlWithoutNamespacesMap().
- Improved json to xml without attributes.
1.84 --
December 1st, 2022
- Added methods U.selectToken(map, expression) and U.selectTokens(map, expression).
- Updated readme.
1.83 --
November 1st, 2022
- Improved methods U.get(), U.set() and U.remove().
- Added methods U.formatJsonOrXml(text) and U.getTextType(text).
1.82 --
October 1st, 2022
- Set up minimum java version 11.
1.81 --
September 2nd, 2022
- Fixed semgrep warning
1.80 --
August 1st, 2022
- Added code analysis semgrep
1.79 --
July 1st, 2022
- Fixed sonar warnings.
1.78 --
June 1st, 2022
- Bumpt to the awaitility 4.2.0.
- Added unit tests toJson and toXml.
- Fixed sonar warnings.
- Added methods U.Builder.get(path) and U.ArrayBuilder.get(path).
- Introduced methods U.Builder.isEmpty() and U.ArrayBuilder.isEmpty().
- Added methods U.Builder.size(), U.Builder.update(map), U.ArrayBuilder.size(), U.ArrayBuilder.merge(list).
1.77 --
May 1st, 2022
- Added new modes FORCE_REMOVE_ARRAY_ATTRIBUTE_JSON_TO_XML and FORCE_REMOVE_ARRAY_BOOLEAN_NUMBER_ATTRIBUTES_JSON_TO_XML to the U.jsonToXml().
1.76 --
April 1st, 2022
- Updated appveyor.yml
- Fixed sonar warnings
- Updated spring-boot-example
1.75 --
March 1st, 2022
- Added methods U.jsonToXml(json, identStep) and U.xmlToJson(xml, identStep).
1.74 --
February 1st, 2022
- Moved classes from package com.github.underscore.lodash to the com.github.underscore.
1.73 --
January 1st, 2022
- Fixed encoding problem for POST and PUT requests.
- Added fetch with retry.
- Added FetchResponse.jsonMap(), FetchResponse.xmlMap() and ObjectBuilder.addMap(map) methods.
- Added methods U.objectBuilder().addNull("Key") and U.arrayBuilder().addNull().
- Fixed sonar warnings.
- Migrated to junit 5.
- Updated dependent libraries for spring-boot example.
- Added StringJoiner to generate json.
- Introduced methods U.downloadUrl(url, fileName) and U.decompressGzip(source, target).
1.72 --
December 1st, 2021
- Added method U.replaceNilWithNull(map).
1.71 --
November 1st, 2021
- Added U.objectBuilder().fromMap(map).
- Changed default format for json and xml with two spaces.
1.70 --
October 1st, 2021
- Added codeql analysis support.
- Added new mode FORCE_ADD_ROOT_JSON_TO_XML to the U.jsonToXml(json, mode, [newRootName]).
- Fixed warning Unsafe hostname verification
1.69 --
September 1st, 2021
- Added windows and sonar builds, added cache maven packages in github actions.
- Renamed com.github.underscore.U with com.github.underscore.Underscore.
- Added new mode REMOVE_FIRST_LEVEL_XML_TO_JSON to the U.xmlToJson() method.
1.68 --
July 1st, 2021
- Added set(path, value) for chain.
- Added Optional.toJavaOptional(), changed Optional.toString().
- Formated source codes.
1.67 --
June 1st, 2021
- Added toChain() method for object and array builder.
- Updated underscore.js with version 1.13.1.
- Added new modes REPLACE_EMPTY_TAG_WITH_NULL and REPLACE_EMPTY_TAG_WITH_EMPTY_STRING for the U.xmlToJson(xml).
- Added new mode REPLACE_EMPTY_STRING_WITH_EMPTY_VALUE to the U.jsonToXml(json).
- Added spring boot example.
- Improved github workflows.
1.66 --
May 1st, 2021
- Added U.mapMulti(list, mapper) method.
1.65 --
April 1st, 2021
- Added new mode REPLACE_NULL_WITH_EMPTY_VALUE to the U.jsonToXml().
1.64 --
March 1st, 2021
- Fixed Template should not fail when value has dollar.
- Improved \r escape in xml.
- Added new mode FORCE_ATTRIBUTE_USAGE_AND_DEFINE_ROOT_NAME to the U.jsonToXml().
- Improved unescape xml attributes.
- Added method U.jsonToXml(json, newRootName).
1.63 --
February 1st, 2021
- Added new mode for jsonToXml() method FORCE_ATTRIBUTE_USAGE.
1.62 --
January 1st, 2021
- Added new mode REPLACE_EMPTY_VALUE_WITH_NULL to the U.xmlToJson() method.
- Added remove(path) and clear() for object and array builder.
1.61 --
December 1st, 2020
- Minimum java version is 1.8
1.60 --
November 1st, 2020
- Added method U.objectBuilder().add("key", U.objectBuilder()).
1.59 --
October 1st, 2020
- Added U.xmlToJson("<a/>", U.Mode.REPLACE_SELF_CLOSING_WITH_EMPTY).
- Introduced U.of(1, 2, 3) // or java.util.Arrays.asList(1, 2, 3) or new Integer[] {1, 2, 3} and toList().
- Fixed initialization error.
1.58 --
September 1st, 2020
- Fixed U.format(pattern, values) with a backslash.
- Added U.minimumDays(rows, columns, grid) method.
- Added U.topNCompetitors(numCompetitors, topNCompetitors, competitors, numReviews, reviews) method.
1.57 --
August 1st, 2020
- Improved U.update(map1, map2).
- Updated dependent libraries.
1.56 --
July 3rd, 2020
- Added U.changeXmlEncoding(xml, encoding).
- Introduced U.setValue(map, key, newValue).
- Added U.update(map1, map2).
- Introduced methods U.gcd(value1, value2) and U.findGcd(value1, ... valuen).
- Improved U.throttle().
1.55 --
June 1st, 2020
- Added Trie class.
- Fixed single cdata section generation in toXml().
- Added U.rename(map, oldKey, newKey).
1.54 --
April 1st, 2020
- Added U.containsWith(iterable, element).
1.53 --
March 1st, 2020
- Fixed U.Builder.toJson() method.
- Fixed null array json converter.
- Improved format json and xml with numbers ending with 0.
- Added U.arrayBuilder().
1.52 --
February 1st, 2020
- Changed parameter for U.times(count, supplier).
- Fixed U.camelCase(string).
- Added method U.countBy(iterator).
- Fixed runtime error for U.format() on android jvm.
- Added U.objectBuilder().
1.51 --
January 2nd, 2020
- Added method U.fromXmlMap(string).
- Added method U.fromJsonMap(string).
- Added method U.isJsonNumber(string).
- Fixed U.capitalize() and U.uncapitalize() methods.
- Added support for type in U.fromJson(string) and U.fromXml(string) methods.
- Added method U.remove(map, key).
1.50 --
December 2nd, 2019
- Added method U.set(map, path, value).
- Added method U.replaceSelfClosingWithNull(map).
- Improved method U.removeMinusesAndConvertNumbers(map).
1.49 --
November 1st, 2019
- Added method U.removeMinusesAndConvertNumbers(map).
- Added mode support for the U.xmlToJson(xml).
1.48 --
October 2nd, 2019
- Added support for Optional.filter(predicate).
1.47 --
August 1st, 2019
- Fixed unexpected return null in Xml.getRootName(localMap).
1.46 --
July 1st, 2019
- Added support for empty processing instruction.
- Added !DOCTYPE support for U.fromXml(xml).
1.45 --
June 1st, 2019
- Fixed long number parser for json and xml.
- Improved createDocument(string).
1.44 --
May 1st, 2019
- Added sum method for array.
- Added U.filter() for iterable.
- Added support for U.nonNull(object).
- Added new chunk() and chunkFilter().
- Added methods U.singleOrNull(iterable) and U.singleOrNull(iterable, predicate).
- Added method U.cycle(iterable, times).
- Added method U.toCardinalityMap(iterable).
- Added U.interpose(iterable, element) and U.interposeByList(iterable, elements) methods.
- Added methods containsAtLeast(iterable, value, count) and containsAtMost(iterable, value, count).
- Added U.splitAt(iterable, position) method.
- Added U.repeat(element, times) method.
- Added U.binarySearch(iterable, value) method.
- Added U.first(iterable, pred, n) method and fixed other U.first() methods.
- Improved U.fill(list, item), added U.fill(array, item) methods.
- Added U.average(iterable) and U.average(iterable, function) methods.
- Added U.explode(string) and U.implode(strings) methods.
- Added U.replace(iterable, predicate, value) and U.replaceIndexed() methods.
- Improved U.concat(iterables) method.
- Added U.takeSkipping(iterable, stepSize) method.
- Added U.subtract(values) method.
- Changed return value for methods U.range(stop), U.range(start, stop) and U.range(start, stop, step).
- Improved U.functions(object) method.
- Removed U.shortestPathAllKeys(grid).
1.43 --
April 1st, 2019
- Added support U.fromXml(xml) for format.
- Introduced U.defaultTo(value, defaultValue).
- Added U.isNotEmpty(interable).
1.42 --
March 1st, 2019
- Added U.shortestPathAllKeys(string[]).
- Fixed pmd warnings.
1.41 --
February 1st, 2019
- Added U.count(iterable, predicate).
- Fixed U.fromXmlWithoutNamespaces(string).
- Added check for #item in U.get(map).
1.40 --
January 1st, 2019
- Improved processing instruction node support.
- Improved external dtd processing in U.fromXml(string).
1.39 --
December 1st, 2018
- Improved format xml without header.
- Improved Euro generation in U.toXml(map).
- Improved standalone parser in xml header.
- Added Xml.fromXmlWithoutNamespaces(string).
- Added U.fromXmlWithoutAttributes(string) and U.fromXmlWithoutNamespacesAndAttributes(string).
- Added processing instruction node support.
1.38 --
November 1st, 2018
- Added self-closing xml element support.
- Improved nested array support.
- Added Optional.isEmpty().
- Improved support for xml with dtd.
- Improved U.every(list, pred).
1.37 --
October 1st, 2018
- Added ident support for U.xmlToJson(string) and U.jsonToXml(string).
- Improved support for text and comments in U.fromXml(string).
- Added U.formatXml(string) and U.formatJson(string) methods.
- Improved U.range(start, stop), updated underscore.js with version 1.91.
- Added sonarcloud support.
1.36 --
September 1st, 2018
- Merged math and string modules to the lodash package.
- Added attributes support for U.fromXml(string) and U.toXml(map).
- Improved escape in U.toXml(object).
- Added U.xmlToJson(string) and U.jsonToXml(string) methods in lodash.
1.35 --
August 3rd, 2018
- Math plugin was moved to the main package.
1.34 --
July 1st, 2018
- Renamed main class from $ to the U.
- Added jdk 9 and jdk 10 support in travis-ci.
1.33 --
June 1st, 2018
- Added support for $.reduce(iterable, function) and $.reduceRigth(iterable, function).
- Added $.groupBy(iterable, function, binaryOperator) method.
- Added $.and(predicates) and $.or(predicates) methods.
1.32 --
May 1st, 2018
- Added support for the $.mapIndexed() and $.forEachIndexed() methods.
- Added $.createLRUCache(capacity) method in lodash module.
- Added $.fromXmlMakeArrays(xml) method in lodash module.
1.31 --
April 1st, 2018
- Renamed Block with Consumer and Function with Supplier.
- Replaced Function1 with Function, remove Function2 and Function4.
- Moved lodash plugin to the main module.
- Renamed FunctionAccum with BiFunction.
1.30 --
February 1st, 2018
- Added check() method for Template.
1.29 --
January 1st, 2018
- Added File, Directory and Entry classes to the math plugin.
- Added $.findByName(entry, name) in math plugin.
- Added root support for the $.fromXml() method in string and lodash plugins.
- Added support for $.get(list, index), $.get(index), $.set(list, index, value) and $.set(index, value) methods.
1.28 --
November 1st, 2017
- Added filterFalse(list, pred) method support.
- Added support for the LRUCache in math plugin.
1.27 --
July 1st, 2017
- Added $.filterIndexed(), $.rejectIndexed(), chain filterIndexed and chain rejectIndexed methods.
- Added object-oriented map(func) method.
- Added object-oriented methods for filter and reject.
1.26 --
June 2nd, 2017
- Added method $.format(template, values).
1.25 --
May 1st, 2017
- Added method $.iterate(seed, unaryOperator).
- Added support for the method $.chain(iterable, size).
- Fixed Chain.uniq(Function<T, F>) method.
1.24 --
Apr 1st, 2017
- Added more checks for the $.fromXml() method in lodash and string plugins.
1.23 --
Feb 2nd, 2017
- Moved push(), pop(), shift() and unshift() to the underscore library.
- Removed each and print support from template.
1.22 --
Jan 2nd, 2017
- Added support for the $.sortWith(list, comparator) method.
1.21 --
Dec 1st, 2016
- Added methods firstOrNull(list), firstOrNull(list, pred), lastOrNull(list) and lastOrNull(list, pred) for chain.
- Added methods $.checkNotNull(), Optional.map(function1) and Optional.orThrow(function).
- Changed newHashSet with newLinkedHashSet for uniq/distinct methods.
- Added lastIndex(array), distinct(array) and distinctBy(array, func) methods.
- Added support for the $.chain(int[]) and $.map(int[], function) methods.
1.20 --
Nov 1st, 2016
- Added more checks for the limit(size) method in chain.
- Added support for the connectTimeout and readTimeout parameters in $.fetch() method, lodash plugin.
- Added xml() method to the FetchResponse.
1.19 --
Oct 1st, 2016
- Improved perfomance for $.intersection(list1, list2) and $.difference(list1, list2) methods.
- Added forEach(inerator) and forEachRight(inerator) for chain.
- Improved $.join(iterable, separator) method.
- Improved $.debounce(function, delay) method and added $.throttle(function, wait) method.
1.18 --
Sep 1st, 2016
- Replaced call for guava collection objects with java collection objects.
- Added createPermutationWithRepetition method to the math plugin.
- Added ScheduledFuture return type support for the $.defer(function) and $.delay(function, delayMilliseconds) methods.
- Added $.fetch(url), $.fetch(url, method, body) and $.fetch(url, method, body, headerFields) methods to the lodash plugin.
1.17 --
Aug 1st, 2016
- Added $.push(values), $.pop(), $.shift() and $.unshift(values) methods to the lodash plugin.
- Added $.copyOf(), $.copyOfRange(start, end), $.elementAt(index), $.elementAtOrElse(index, defaultValue) and $.elementAtOrNull(index) methods support.
- Changed argument type for the template.apply(map) method.
1.16 --
Jul 1st, 2016
- Added $.memoize(function) method.
- Added support for the get(object, path) method in lodash plugin.
1.15 --
Jun 1st, 2016
- Made max parameter inclusive in random method
- Added $.random(int max) method support
1.14 --
May 1st, 2016
- Added new methods: first(list, predicate), firstOrNull(list), firstOrNull(list, predicate), last(list, predicate), lastOrNull(list), lastOrNull(list, predicate)
1.13 --
Apr 1st, 2016
- Added support for the setTimeout(), clearTimeout(), setInterval() and clearInterval() methods
1.12 --
Mar 1st, 2016
- Renamed trimLeft, trimRight, padLeft, padRight to the trimStart, trimEnd, padStart, padEnd in string and lodash plugins
- Improved once(), after() and before() methods. They returned last stored result for now
1.11 --
Feb 4th, 2016
- Added support for the toMap() method with list of tuples
- Added compact() support for the chain()
1.10 --
Jan 1st, 2016
- Removed redundant type casting
- Added support for the toJsonJavaString() method in string plugin
- Added support for the fromXml() method in string and lodash plugins
- Fixed max password length in uniquePassword() method
- Added examples for methods intersection and xor, snakeCase, chaining, fromXml and fromJson
1.9 --
Dec 1st, 2015
- Improved toJson() method in string and lodash plugins
- Added support for the uniquePassword() to generate 8-15 length passwords
- Improved return types in chain() methods
- Improved escape/unescape methods
- Added java8 unit test examples
1.8 --
Nov 1st, 2015
- Added methods fromNullable(), or() and orNull() for the Optional class
- Added support for the toXml() method in string and lodash plugins
- Fixed unicode parser in string and lodash plugins
- Added support for the methods upperFirst and lowerFirst in string and lodash plugins
- Fixed compiler warnings
1.7 --
Oct 1st, 2015
- Added support for the range() methods in chain()
- Added support for the method sum(array, function) in math and lodash plugins
- Added chain methods in lodash, math and string plugins
- Added support for better formatting in toJson() method in string and lodash plugins
- Added support for the cyrillic characters in words() method in string and lodash plugins
1.6 --
Sep 1st, 2015
- Added support for the method chunk(array, size)
- Added support for the method name in where() and findWhere() methods
- Added support for the methods toJson() and fromJson() in lodash and string plugins
- Added support for the object and chain methods invoke(), pluck(), where(), findWhere(), max() and min()
- Added read class data by method name into pluck()
1.5 --
Aug 1st, 2015
- Added toMap(), value(), chain(), eachRight(), and forEachRight()
- Added chain and object methods support for the size() and isEmpty()
- Fixed type for sort() method
- Added support for the chain methods every() and some()
- Added chain methods support groupBy(), indexBy() and countBy()
- Added support for the diferrence(arrays) and union(arrays) methods
- Improve equals and hashCode for Optional
1.4 -- July 1st, 2015
- Fixed slice(0, N) method
- List generators available for plugins
- Added parameters check for first, last, rest and initial methods
- Introduced underscore-lodash plugin
1.3 -- June 1st, 2015
- Main class was renamed from _ to the $.
- Methods were reordered
- Unit tests were divided by groups
- New methods were added
- Math plugin was added
1.2 -- May 1st, 2015
- Added methods initial, rest, last to the _.chain().
1.1 -- April 4th, 2015
- Add support for the methods filter and reject to the chain object
1.0 -- December 27, 2014
- Main functionality was implemented
