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.
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)); // 100 U.max(asList(10, 5, 100, 2, 1000), new Function<Integer, Integer>() { public Integer apply(Integer item) { return -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), new Function<Integer, Integer>() { public Integer apply(Integer item) { return -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), new Function<Integer, Integer>() { public Integer apply(Integer item) { return 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), new Function<Double, Double>() { public Double apply(Double num) { return Math.floor(num); } });
=> {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)), new Function<Person, String>() { public String apply(Person person) { return 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
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]
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!';
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
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"
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]
1.107 --
November 1st, 2024
1.106 --
October 1st, 2024
1.105 --
September 1st, 2024
1.104 --
August 1st, 2024
1.103 --
July 1st, 2024
1.102 --
June 1st, 2024
1.101 --
May 1st, 2024
1.100 --
April 1st, 2024
1.99 --
March 1st, 2024
1.98 --
February 1st, 2024
1.97 --
January 1st, 2024
1.96 --
December 1st, 2023
1.95 --
November 1st, 2023
1.94 --
October 1st, 2023
1.93 --
September 1st, 2023
1.92 --
August 1st, 2023
1.91 --
July 2nd, 2023
1.90 --
June 1st, 2023
1.89 --
May 1st, 2023
1.88 --
April 1st, 2023
1.87 --
March 1st, 2023
1.86 --
February 1st, 2023
1.85 --
January 2nd, 2023
1.84 --
December 1st, 2022
1.83 --
November 1st, 2022
1.82 --
October 1st, 2022
1.81 --
September 2nd, 2022
1.80 --
August 1st, 2022
1.79 --
July 1st, 2022
1.78 --
June 1st, 2022
1.77 --
May 1st, 2022
1.76 --
April 1st, 2022
1.75 --
March 1st, 2022
1.74 --
February 1st, 2022
1.73 --
January 1st, 2022
1.72 --
December 1st, 2021
1.71 --
November 1st, 2021
1.70 --
October 1st, 2021
1.69 --
September 1st, 2021
1.68 --
July 1st, 2021
1.67 --
June 1st, 2021
1.66 --
May 1st, 2021
1.65 --
April 1st, 2021
1.64 --
March 1st, 2021
1.63 --
February 1st, 2021
1.62 --
January 1st, 2021
1.61 --
December 1st, 2020
1.60 --
November 1st, 2020
1.59 --
October 1st, 2020
1.58 --
September 1st, 2020
1.57 --
August 1st, 2020
1.56 --
July 3rd, 2020
1.55 --
June 1st, 2020
1.54 --
April 1st, 2020
1.53 --
March 1st, 2020
1.52 --
February 1st, 2020
1.51 --
January 2nd, 2020
1.50 --
December 2nd, 2019
1.49 --
November 1st, 2019
1.48 --
October 2nd, 2019
1.47 --
August 1st, 2019
1.46 --
July 1st, 2019
1.45 --
June 1st, 2019
1.44 --
May 1st, 2019
1.43 --
April 1st, 2019
1.42 --
March 1st, 2019
1.41 --
February 1st, 2019
1.40 --
January 1st, 2019
1.39 --
December 1st, 2018
1.38 --
November 1st, 2018
1.37 --
October 1st, 2018
1.36 --
September 1st, 2018
1.35 --
August 3rd, 2018
1.34 --
July 1st, 2018
1.33 --
June 1st, 2018
1.32 --
May 1st, 2018
1.31 --
April 1st, 2018
1.30 --
February 1st, 2018
1.29 --
January 1st, 2018
1.28 --
November 1st, 2017
1.27 --
July 1st, 2017
1.26 --
June 2nd, 2017
1.25 --
May 1st, 2017
1.24 --
Apr 1st, 2017
1.23 --
Feb 2nd, 2017
1.22 --
Jan 2nd, 2017
1.21 --
Dec 1st, 2016
1.20 --
Nov 1st, 2016
1.19 --
Oct 1st, 2016
1.18 --
Sep 1st, 2016
1.17 --
Aug 1st, 2016
1.16 --
Jul 1st, 2016
1.15 --
Jun 1st, 2016
1.14 --
May 1st, 2016
1.13 --
Apr 1st, 2016
1.12 --
Mar 1st, 2016
1.11 --
Feb 4th, 2016
1.10 --
Jan 1st, 2016
1.9 --
Dec 1st, 2015
1.8 --
Nov 1st, 2015
1.7 --
Oct 1st, 2015
1.6 --
Sep 1st, 2015
1.5 --
Aug 1st, 2015
1.4 -- July 1st, 2015
1.3 -- June 1st, 2015
1.2 -- May 1st, 2015
1.1 -- April 4th, 2015
1.0 -- December 27, 2014