All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.lambdaj.Lambda Maven / Gradle / Ivy

// Modified or written by Ex Machina SAGL for inclusion with lambdaj.
// Copyright (c) 2009 Mario Fusco, Luca Marrocco.
// Licensed under the Apache License, Version 2.0 (the "License")

package ch.lambdaj;

import static ch.lambdaj.function.argument.ArgumentsFactory.*;
import static ch.lambdaj.function.closure.ClosuresFactory.*;
import static ch.lambdaj.function.matcher.HasArgumentWithValue.*;
import static ch.lambdaj.util.iterator.IteratorFactory.*;
import ch.lambdaj.util.iterator.*;

import java.util.*;

import org.hamcrest.*;

import ch.lambdaj.function.aggregate.*;
import ch.lambdaj.function.argument.*;
import ch.lambdaj.function.closure.*;
import ch.lambdaj.function.compare.*;
import ch.lambdaj.function.convert.*;
import ch.lambdaj.function.matcher.*;
import ch.lambdaj.proxy.*;

/**
 * This class consists exclusively of static methods that allow to use all the core features of the lambdaj library.
 * @author Mario Fusco
 */
@SuppressWarnings("unchecked")
public final class Lambda {
	
	private Lambda() { }
	
	/**
	 * Constructs a proxy object that mocks the given Class registering all the subsequent invocations on the object.
	 * @param clazz The class of the object to be mocked
	 * @return An object of the given class that register all the invocations made on it
	 */
	public static  T on(Class clazz) {
		return createArgument(clazz);
	}
	
	/**
	 * Returns the actual argument of the methods invocation sequence defined through the {@link Lambda#on(Class)} method.
	 * @param argumentPlaceholder The placeholder for this argument created using the {@link Lambda#on(Class)} method
     * @return The actual argument of the methods invocation sequence defined through the {@link Lambda#on(Class)} method
	 */
	public static  Argument argument(T argumentPlaceholder) {
		return actualArgument(argumentPlaceholder);
	}

	/**
	 * Transforms a collection of Ts in a single object having the same methods of a single instance of T.
	 * That allows to invoke a method on each T in the collection with a single strong typed method call as in the following example:
	 * 
	 * 		List<Person> personInFamily = asList(new Person("Domenico"), new Person("Mario"), new Person("Irma"));
	 *		forEach(personInFamily).setLastName("Fusco");
	 * 
* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param The type of the items in the iterable * @param iterable The iterable to be transformed * @return An object that proxies all the item in the iterable or null if the iterable is null or empty * @throws IllegalArgumentException if the iterable is null or empty */ public static T forEach(Iterable iterable) { ResettableIterator resettableIterator = (ResettableIterator)asResettableIterator(iterable); if (!resettableIterator.hasNext()) throw new IllegalArgumentException("forEach() is unable to introspect on an empty iterator. Use the overloaded method accepting a class instead"); return ProxyIterator.createProxyIterator(resettableIterator, resettableIterator.next()); } /** * Transforms a collection of Ts in a single object having the same methods of a single instance of T. * That allows to invoke a method on each T in the collection with a single strong typed method call. * The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param The type of the items in the iterable * @param iterator The iterator to be transformed * @return An object that proxies all the item in the iterator or null if the iterator is null or empty * @throws IllegalArgumentException if the iterable is null or empty */ public static T forEach(Iterator iterator) { if (!iterator.hasNext()) throw new IllegalArgumentException("forEach() is unable to introspect on an empty iterator. Use the overloaded method accepting a class instead"); ResettableIterator resettableIterator = (ResettableIterator)asResettableIterator(iterator); return ProxyIterator.createProxyIterator(resettableIterator, resettableIterator.next()); } /** * Transforms a collection of Ts in a single object having the same methods of a single instance of T. * That allows to invoke a method on each T in the collection with a single strong typed method call as in the following example: *
	 * 		List<Person> personInFamily = asList(new Person("Domenico"), new Person("Mario"), new Person("Irma"));
	 *		forEach(personInFamily, Person.class).setLastName("Fusco");
	 * 
* The given class represents the proxied by the returned object, so it should be a superclass of all the objects in the iterable. * This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param The type of the items in the iterable * @param iterable The iterable to be transformed * @param clazz The class proxied by the returned object * @return An object that proxies all the item in the iterable. If the given iterable is null or empty it returns * an instance of T that actually proxies an empty Iterable of Ts */ public static T forEach(Iterable iterable, Class clazz) { return ProxyIterator.createProxyIterator((ResettableIterator)asResettableIterator(iterable), clazz); } /** * Transforms an iterator of Ts in a single object having the same methods of a single instance of T. * That allows to invoke a method on each T in the iterator with a single strong typed method call. * The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param The type of the items in the iterator * @param iterator The iterator to be transformed * @param clazz The class proxied by the returned object * @return An object that proxies all the item in the iterator or null if the iterator is null or empty * @throws IllegalArgumentException if the iterator is null or empty */ public static T forEach(Iterator iterator, Class clazz) { return ProxyIterator.createProxyIterator((ResettableIterator)asResettableIterator(iterator), clazz); } /** * Transforms an array of Ts in a single object having the same methods of a single instance of T. * That allows to invoke a method on each T in the array with a single strong typed method call. * @param The type of the items in the array * @param array The array to be transformed * @return An object that proxies all the item in the array */ public static T forEach(T... array) { return ProxyIterator.createProxyIterator((ResettableIterator)asResettableIterator(array), (Class)array[0].getClass()); } // //////////////////////////////////////////////////////////////////////// // /// Collection // //////////////////////////////////////////////////////////////////////// /** * Flattens the given iterable by recursively descending through its nested Collections * and create a flat List of all of the leaves. * This method also works with Maps (by collecting their values) and arrays. * @param iterable The iterable to be flattened * @return The flattened iterable */ public static List flatten(Object iterable) { return flattenIterator(iterable); } /** * Collects the items in the given iterable putting them in a List. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of which the items should be collected * @return A List containing all the items collected from the give iterable * @throws IllegalArgumentException if the iterable is not an Iterable or a Map */ public static List collect(Object iterable) { List collected = new ArrayList(); Iterator i = asIterator(iterable); while (i.hasNext()) { Object item = i.next(); if (item instanceof Iterable) collected.addAll((Collection) collect(item)); else if (item instanceof Map) collected.addAll((Collection) collect(((Map)item).values())); else collected.add((T)item); } return collected; } /** * For each item in the given iterable collects the value defined by the given argument and put them in a List. * For example the following code: *
	 * 		List<Person> myFriends = asList(new Person("Biagio", 39), new Person("Luca", 29), new Person("Celestino", 29));
	 *		List<Integer> ages = collect(meAndMyFriends, on(Person.class).getAge());
	 * 
* extracts the ages of all the Persons in the list and put them in a List of Integer. *

* Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of which the items should be collected * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A List containing all the items collected from the give iterable * @throws RuntimeException if the iterable is not an Iterable or a Map */ public static List collect(Object iterable, T argument) { return (List)collect(convert(iterable, new ArgumentConverter(argument))); } // //////////////////////////////////////////////////////////////////////// // /// Sort // //////////////////////////////////////////////////////////////////////// /** * Sorts all the items in the given iterable on the respective values of the given argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be sorted * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A List with the same items of the given iterable sorted on the respective value of the given argument */ public static List sort(Object iterable, Object argument) { return sort(iterable, argument, null); } /** * Sorts all the items in the given iterable on the respective values of the given argument comparing them with the given comparator. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be sorted * @param argument An argument defined using the {@link Lambda#on(Class)} method * @param comparator The comparator to determine the order of the list. A null value indicates that the elements' natural ordering should be used * @return A List with the same items of the given iterable sorted on the respective value of the given argument */ public static List sort(Object iterable, A argument, Comparator comparator) { List sorted = new ArrayList(); for (Iterator i = asIterator(iterable); i.hasNext();) sorted.add((T)i.next()); Collections.sort(sorted, new ArgumentComparator(argument, comparator)); return sorted; } // //////////////////////////////////////////////////////////////////////// // /// Selection // //////////////////////////////////////////////////////////////////////// /** * Filters all the objects in the given iterable that match the given hamcrest Matcher * @param matcher The hamcrest Matcher used to filter the given iterable * @param iterable The iterable of objects to be filtered * @return A sublist of the given iterable containing all the objects that match the given hamcrest Matcher */ public static List filter(Matcher matcher, Iterable iterable) { return select(iterable, matcher); } /** * Filters all the objects in the given array that match the given hamcrest Matcher * @param matcher The hamcrest Matcher used to filter the given array * @param array The array of objects to be filtered * @return A sublist of the given array containing all the objects that match the given hamcrest Matcher */ public static List filter(Matcher matcher, T... array) { return select(array, matcher); } /** * Selects all the objects in the given iterator that match the given hamcrest Matcher * @param iterator The iterator of objects to be filtered * @param matcher The hamcrest Matcher used to filter the given iterable * @return A sublist of the given iterable containing all the objects that match the given hamcrest Matcher */ public static List select(Iterator iterator, Matcher matcher) { List collected = new ArrayList(); while (iterator.hasNext()) { T item = iterator.next(); if (matcher.matches(item)) collected.add(item); } return collected; } /** * Selects all the objects in the given iterable that match the given hamcrest Matcher * @param iterable The iterable of objects to be filtered * @param matcher The hamcrest Matcher used to filter the given iterable * @return A sublist of the given iterable containing all the objects that match the given hamcrest Matcher */ public static List select(Iterable iterable, Matcher matcher) { return select(iterable.iterator(), matcher); } /** * Selects all the objects in the given iterable that match the given hamcrest Matcher * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param matcher The hamcrest Matcher used to filter the given iterable * @return A sublist of the given iterable containing all the objects that match the given hamcrest Matcher */ public static List select(Object iterable, Matcher matcher) { return select((Iterator)asIterator(iterable), matcher); } /** * Selects all the objects in the given iterable that match the given hamcrest Matcher * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * Unlike the method {@link #select(Iterable, Matcher)} this one doesn't build a new collection, and the * selection is done while iterating the returned iterator. * @param iterable The iterable of objects to be filtered * @param matcher The hamcrest Matcher used to filter the given iterable * @return An iterator containing all the objects in the given iterable converted using the given {@link Converter} */ public static Iterator selectIterator(Object iterable, Matcher matcher) { return new MatchingIterator((Iterator) asIterator(iterable), matcher); } /** * Selects the unique object in the given iterable that matches the given hamcrest Matcher * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param matcher The hamcrest Matcher used to filter the given iterable * @return The only object in the given iterable that matches the given hamcrest Matcher or null if there is no such object * @throws RuntimeException if there is more than one object that matches the given hamcrest Matcher */ public static T selectUnique(Object iterable, Matcher matcher) { Iterator iterator = new MatchingIterator(asIterator(iterable), matcher); if (!iterator.hasNext()) return null; T unique = iterator.next(); if (iterator.hasNext()) throw new RuntimeException("Not unique item"); return unique; } /** * Selects the first object in the given iterable that matches the given hamcrest Matcher * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param matcher The hamcrest Matcher used to filter the given iterable * @return The first object in the given iterable that matches the given hamcrest Matcher or null if there is no such object */ public static T selectFirst(Object iterable, Matcher matcher) { Iterator iterator = (Iterator)asIterator(iterable); while (iterator.hasNext()) { T item = iterator.next(); if (matcher.matches(item)) return item; } return null; } /** * Filters away all the duplicated items in the given iterable. * @param iterable The iterable of objects to be filtered * @return A Collection with the same items of the given iterable but containing no duplicate elements */ public static Collection selectDistinct(Iterable iterable) { return selectDistinct(iterable, (Comparator) null); } /** * Filters away all the duplicated items in the given iterable. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @return A Collection with the same items of the given iterable but containing no duplicate elements */ public static Collection selectDistinct(Object iterable) { return selectDistinct(iterable, (Comparator) null); } /** * Selects all the items in the given iterable having a different value in the named property. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param propertyName The name of the item's property on which the item must have no duplicated value * @return A Collection with the same items of the given iterable but containing no duplicate values on the named property */ public static Collection selectDistinct(Object iterable, String propertyName) { return selectDistinct(iterable, new PropertyComparator(propertyName)); } /** * Selects all the items in the given iterable having a different value on the given argument defined using the on method. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A Collection with the same items of the given iterable but containing no duplicate values on the given argument */ public static Collection selectDistinctArgument(Object iterable, A argument) { return selectDistinct(iterable, new ArgumentComparator(argument)); } /** * Filters away all the duplicated items in the given iterable based on the given comparator. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param comparator The comparator used to decide if 2 items are different or not * @return A Collection with the same items of the given iterable but containing no duplicate elements */ public static Collection selectDistinct(Object iterable, Comparator comparator) { Set collected = comparator == null ? new HashSet() : new TreeSet(comparator); for (Iterator i = (Iterator)asIterator(iterable); i.hasNext();) collected.add(i.next()); return collected; } /** * Selects the item in the given iterable having the lowest value on the given argument defined using the on method. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return The item in the given iterable with the minimum value on the given argument */ public static T selectMin(Object iterable, A argument) { return aggregate(iterable, new MinOnArgument(argument)); } /** * Selects the item in the given iterable having the highest value on the given argument defined using the on method. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects to be filtered * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return The item in the given iterable with the maximum value on the given argument */ public static T selectMax(Object iterable, A argument) { return aggregate(iterable, new MaxOnArgument(argument)); } // //////////////////////////////////////////////////////////////////////// // /// Aggregation // //////////////////////////////////////////////////////////////////////// private static Aggregator getSumAggregator(Object object) { if (object instanceof Integer) return new SumInteger((Integer)object); if (object instanceof Double) return new SumDouble((Double)object); if (object instanceof Long) return new SumLong((Long)object); return new Sum((Number)object); } private static final Sum Sum = new Sum(); private static final Min Min = new Min(); private static final Max Max = new Max(); private static final Concat Concat = new Concat(); /** * Aggregates the items in the given iterable using the given {@link Aggregator}. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of numbers to be summed * @param aggregator The function that defines how the objects in this iterable have to be aggregated * @return The result of the aggregation of all the items in the given iterable * @throws RuntimeException if the iterable is not an Iterable */ public static T aggregate(Object iterable, Aggregator aggregator) { return aggregator.aggregate((Iterator)asIterator(iterable)); } /** * For each item in the given iterable collects the value defined by the given argument and * then aggregates them iterable using the given {@link Aggregator}. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of numbers to be summed * @param aggregator The function that defines how the objects in this iterable have to be aggregated * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return The result of the aggregation of all the items in the given iterable * @throws RuntimeException if the iterable is not an Iterable */ public static T aggregate(Object iterable, Aggregator aggregator, A argument) { return aggregate(convertIterator(iterable, new ArgumentConverter(argument)), aggregator); } /** * Returns a lambda function defined as: *

* aggregateFrom : (aggregator, iterable) => lambda : (convert : object => object) => object *

* It is then possibly to curry this function by selecting the convert function that defines how each item must be converted in the object to be aggregated. * This is done by invoking on that returned object the method that returns the values of the property to be aggregated. * @param iterable The iterable of the objects to containing the property to be aggregated. * @param aggregator The function that defines how the objects in this iterable have to be aggregated * @return A proxy of the class of the first object in the iterable representing an aggregation lambda function * @throws IllegalArgumentException if the iterable is null or empty */ public static T aggregateFrom(Iterable iterable, Aggregator aggregator) { Iterator iterator = (Iterator)asIterator(iterable); if (!iterator.hasNext()) throw new IllegalArgumentException("aggregateFrom() is unable to introspect on an empty iterator. Use the overloaded method accepting a class instead"); return aggregateFrom(iterable, iterator.next().getClass(), aggregator); } /** * Returns a lambda function defined as: *

* aggregateFrom : (aggregator, iterable) => lambda : (convert : object => object) => object *

* It is then possibly to curry this function by selecting the convert function that defines how each item must be converted in the object to be aggregated. * This is done by invoking on that returned object the method that returns the values of the property to be aggregated. * This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param iterable The iterable of the objects to containing the property to be aggregated. * @param clazz The class proxied by the returned object * @param aggregator The function that defines how the objects in this iterable have to be aggregated * @return A proxy of the class of the first object in the iterable representing an aggregation lambda function */ public static T aggregateFrom(Iterable iterable, Class clazz, Aggregator aggregator) { return ProxyAggregator.createProxyAggregator((ResettableIterator) asResettableIterator(iterable), aggregator, clazz); } // -- (Sum) --------------------------------------------------------------- /** * Sums the items in the given iterable of Numbers or the iterable itself if it actually is already a single number. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of numbers to be summed * @return The sum of all the Number in the given iterable or the iterable itself if it actually is already a single number * @throws IllegalArgumentException if the iterable is not neither an Iterable nor a Number */ public static Number sum(Object iterable) { if (iterable instanceof Number) return (Number)iterable; Iterator iterator = asIterator(iterable); return iterator.hasNext() ? aggregate(iterator, getSumAggregator(iterator.next())) : 0.0; } /** * Sums the property values of the items in the given iterable defined by the given argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of items containing the property of which the values have to be summed. * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return The sum of the property values extracted from all the items in the given iterable * @throws IllegalArgumentException if the iterable is not an Iterable */ public static T sum(Object iterable, T argument) { return (T)sum(convertIterator(iterable, new ArgumentConverter(argument))); } /** * Returns a lambda function defined as: *

* sumFrom : (+, iterable) => lambda : (convert : object => number) => number *

* It is then possibly to curry this function by selecting the convert function that defines of each item must be converted in a number. * This is done by invoking on that returned object the method that returns the values of the property to be summed as in the following example *

* * int totalAge = sumFrom(persons).getAge(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param iterable The iterable of the objects to containing the property to be summed. * @return A proxy of the class of the first object in the iterable representing a sum lambda function * @throws IllegalArgumentException if the iterable is null or empty */ public static T sumFrom(Iterable iterable) { return aggregateFrom(iterable, Sum); } /** * Returns a lambda function defined as: *

* sumFrom : (+, iterable) => lambda : (convert : object => number) => number *

* It is then possibly to curry this function by selecting the convert function that defines of each item must be converted in a number. * This is done by invoking on that returned object the method that returns the values of the property to be summed as in the following example *

* * int totalAge = sumFrom(persons, Person.class).getAge(); * *

* This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param iterable The iterable of the objects to containing the property to be summed. * @param clazz The class proxied by the returned object * @return A proxy of the class of the first object in the iterable representing a sum lambda function */ public static T sumFrom(Iterable iterable, Class clazz) { return aggregateFrom(iterable, clazz, Sum); } // -- (Min) --------------------------------------------------------------- /** * Finds the minimum item in the given iterable. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of numbers to be summed * @return The minimum of all the Object in the given iterable * @throws IllegalArgumentException if the iterable is not an Iterable */ public static T min(Object iterable) { return (T) aggregate(iterable, Min); } /** * Finds the minimum item in the given iterable defined by the given argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects on which the minimum should be found * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return The minimum of all the Object in the given iterable * @throws IllegalArgumentException if the iterable is not an Iterable */ public static T min(Object iterable, T argument) { return (T)aggregate(iterable, Min, argument); } /** * Returns a lambda function defined as: *

* minFrom : (min, iterable) => lambda : (convert : object => object) => object *

* It is then possibly to curry this function by selecting the convert function that defines how each item * must be converted in the object of which a minimum value needs to be found. * This is done by invoking on that returned object the method that returns the values of the property to be aggregated. *

* * int minAge = maxFrom(persons).getAge(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param iterable The iterable of objects on which the minimum should be found * @return A proxy of the class of the first object in the iterable representing a min lambda function * @throws IllegalArgumentException if the iterable is null or empty */ public static T minFrom(Iterable iterable) { return (T) aggregateFrom(iterable, Min); } /** * Returns a lambda function defined as: *

* minFrom : (min, iterable) => lambda : (convert : object => object) => object *

* It is then possibly to curry this function by selecting the convert function that defines how each item * must be converted in the object of which a minimum value needs to be found. * This is done by invoking on that returned object the method that returns the values of the property to be aggregated. *

* * int minAge = minFrom(persons).getAge(); * *

* This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param iterable The iterable of the objects containing the property of which the minimum should be found. * @param clazz The class proxied by the returned object * @return A proxy of the class of the first object in the iterable representing a min lambda function */ public static T minFrom(Iterable iterable, Class clazz) { return (T) aggregateFrom(iterable, clazz, Min); } // -- (Max) --------------------------------------------------------------- /** * Finds the maximum item in the given iterable. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects on which the maximum should be found * @return The maximum of all the Object in the given iterable * @throws IllegalArgumentException if the iterable is not an Iterable */ public static T max(Object iterable) { return (T) aggregate(iterable, Max); } /** * Finds the maximum item in the given iterable defined by the given argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable of objects on which the maximum should be found * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return The maximum of all the Object in the given iterable * @throws IllegalArgumentException if the iterable is not an Iterable */ public static T max(Object iterable, T argument) { return (T)aggregate(iterable, Max, argument); } /** * Returns a lambda function defined as: *

* maxFrom : (max, iterable) => lambda : (convert : object => object) => object *

* It is then possibly to curry this function by selecting the convert function that defines how each item * must be converted in the object of which a maximum value needs to be found. * This is done by invoking on that returned object the method that returns the values of the property to be aggregated. *

* * int maxAge = maxFrom(persons).getAge(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param iterable The iterable of objects on which the maximum should be found * @return A proxy of the class of the first object in the iterable representing a max lambda function * @throws IllegalArgumentException if the iterable is null or empty */ public static T maxFrom(Iterable iterable) { return (T) aggregateFrom(iterable, Max); } /** * Returns a lambda function defined as: *

* maxFrom : (max, iterable) => lambda : (convert : object => object) => object *

* It is then possibly to curry this function by selecting the convert function that defines how each item * must be converted in the object of which a maximum value needs to be found. * This is done by invoking on that returned object the method that returns the values of the property to be aggregated. *

* * int maxAge = maxFrom(persons).getAge(); * *

* This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param iterable The iterable of the objects containing the property of which the maximum should be found. * @param clazz The class proxied by the returned object * @return A proxy of the class of the first object in the iterable representing a max lambda function */ public static T maxFrom(Iterable iterable, Class clazz) { return (T) aggregateFrom(iterable, clazz, Max); } // -- (Join) -------------------------------------------------------------- /** * Returns a lambda function defined as: *

* joinFrom : (concat, iterable) => lambda : (convert : object => object) => string *

* It is then possibly to curry this function by selecting the convert function that defines of each item must be converted in a String. * This is done by invoking on that returned object the method that returns the values of the property to be summed as in the following example *

* * String names = joinFrom(persons).getFirstName(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param iterable The iterable of the objects to containing the property to be joined. * @return A proxy of the class of the first object in the iterable representing a join lambda function * @throws IllegalArgumentException if the iterable is null or empty */ public static T joinFrom(Iterable iterable) { return aggregateFrom(iterable, Concat); } /** * Returns a lambda function defined as: *

* joinFrom : (concat, iterable) => lambda : (convert : object => object) => string *

* It is then possibly to curry this function by selecting the convert function that defines of each item must be converted in a String. * This is done by invoking on that returned object the method that returns the values of the property to be summed as in the following example *

* * String names = joinFrom(persons, " - ").getFirstName(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * @param iterable The iterable of the objects to containing the property to be joined. * @param separator The String used to separe the Strings produced by this lambda function * @return A proxy of the class of the first object in the iterable representing a join lambda function * @throws IllegalArgumentException if the iterable is null or empty */ public static T joinFrom(Iterable iterable, String separator) { return aggregateFrom(iterable, new Concat(separator)); } /** * Returns a lambda function defined as: *

* joinFrom : (concat, iterable) => lambda : (convert : object => object) => string *

* It is then possibly to curry this function by selecting the convert function that defines of each item must be converted in a String. * This is done by invoking on that returned object the method that returns the values of the property to be summed as in the following example *

* * String names = joinFrom(persons, Person.class).getFirstName(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param iterable The iterable of the objects to containing the property to be joined. * @param clazz The class proxied by the returned object * @return A proxy of the class of the first object in the iterable representing a join lambda function */ public static T joinFrom(Iterable iterable, Class clazz) { return aggregateFrom(iterable, clazz, Concat); } /** * Returns a lambda function defined as: *

* joinFrom : (concat, iterable) => lambda : (convert : object => object) => string *

* It is then possibly to curry this function by selecting the convert function that defines of each item must be converted in a String. * This is done by invoking on that returned object the method that returns the values of the property to be summed as in the following example *

* * String names = joinFrom(persons, Person.class, " - ").getFirstName(); * *

* The actual class of T is inferred from the class of the first iterable's item, but you can * specify a particular class by using the overloaded method. * This overloaded version should be always used when it is not insured that the given iterable is null or empty. * @param iterable The iterable of the objects to containing the property to be joined. * @param clazz The class proxied by the returned object * @param separator The String used to separe the Strings produced by this lambda function * @return A proxy of the class of the first object in the iterable representing a join lambda function */ public static T joinFrom(Iterable iterable, Class clazz, String separator) { return aggregateFrom(iterable, clazz, new Concat(separator)); } /** * Joins all the object in the given iterable by concatenating all their String representation. * It invokes toString() an all the objects and concatening them using the default separator ", ". * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be joined * @return The concatenation of the String representation of all the objects in the given iterable or an empty String if the iterable is null or empty */ public static String join(Object iterable) { return join(iterable, ", "); } /** * Joins all the object in the given iterable by concatenating all their String representation. * It invokes toString() an all the objects and concatening them using the given separator. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be joined * @param separator The String used to separe the item's String representation * @return The concatenation of the String representation of all the objects in the given iterable or an empty String if the iterable is null or empty */ public static String join(Object iterable, String separator) { return iterable instanceof Iterable ? (String) aggregate(iterable, new Concat(separator)) : (iterable == null ? "" : iterable.toString()); } // //////////////////////////////////////////////////////////////////////// // /// Conversion // //////////////////////////////////////////////////////////////////////// /** * Converts all the object in the iterable using the given {@link Converter}. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be converted * @param converter The converter that specifies how each object in the iterable must be converted * @return A list containing all the objects in the given iterable converted using the given {@link Converter} */ public static List convert(Object iterable, Converter converter) { List collected = new ArrayList(); for (Iterator i = convertIterator(iterable, converter); i.hasNext();) collected.add(i.next()); return collected; } /** * Converts all the object in the iterable using the given {@link Converter}. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be converted * @param converter The converter that specifies how each object in the iterable must be converted * @return An Iterator on all the objects in the given iterable converted using the given {@link Converter} */ public static Iterator convertIterator(Object iterable, Converter converter) { return new ConverterIterator(converter, asIterator(iterable)); } /** * Converts all the object in the iterable extracting the property defined by the given argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be converted * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A list containing the argument's value extracted from the object in the given iterable */ public static List extract(Object iterable, T argument) { return convert(iterable, new ArgumentConverter(argument)); } /** * Converts all the object in the iterable extracting the property defined by the given argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Unlike the method {@link #extract(Object, Object)} this one doesn't build a new collection, and the * extraction is done only when someone iterates over the returned iterator. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be converted * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A list containing the argument's value extracted from the object in the given iterable */ public static Iterator extractIterator(Object iterable, T argument) { return convertIterator(iterable, new ArgumentConverter(argument)); } /** * Converts all the object in the iterable in its String representation. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be converted in strings * @return A list containing the String representation of the objects in the given iterable */ public static List extractString(Object iterable) { return convert(iterable, new DefaultStringConverter()); } /** * Converts all the object in the iterable extracting the named property. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be converted * @param propertyName The name of the item's property on which the item must have no duplicated value * @return A list containing the property's value extracted from the object in the given iterable */ public static List extractProperty(Object iterable, String propertyName) { return convert(iterable, new PropertyExtractor(propertyName)); } /** * Maps the objects in the given iterable on the value extracted using the given {@link Converter}. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be mapped * @param converter The converter that specifies the key on which each object should be mapped * @return A map having as keys the argument value extracted from the objects in the given iterable and as values the corresponding objects */ public static Map map(Object iterable, Converter converter) { Map map = new HashMap(); Iterator i = (Iterator)asIterator(iterable); while (i.hasNext()) { F item = i.next(); map.put(converter.convert(item), item); } return map; } /** * Indexes the objects in the given iterable based on the value of their argument. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be indexed * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A map having as keys the argument value extracted from the objects in the given iterable and as values the corresponding objects */ public static Map index(Object iterable, T argument) { return map(iterable, new ArgumentConverter(argument)); } /** * Converts the objects in the given iterable in objects of the given target Class. * The objects are created by invoking its constructor passing to it the values taken * from the object to be converted using the given arguments. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be projected * @param targetClass The class in which the objects in the given iterable must be converted * @param arguments The arguments of the objects to be converted that will be used to create the objects of the target class * @return A list of map where each map is the result of the projection of an object in the iterable */ public static List project(Object iterable, Class targetClass, Object... arguments) { return convert(iterable, new ConstructorArgumentConverter(targetClass, arguments)); } /** * Projects the objects in the given iterable by converting each of them in a set of key/value pairs. * Actually it handles also Maps, Arrays and Iterator by collecting their values. * Note that this method accepts an Object in order to be used in conjunction with the {@link Lambda#forEach(Iterable)}. * @param iterable The iterable containing the objects to be projected * @param projectors The converters that define how each object should be projected * @return A list of map where each map is the result of the projection of an object in the iterable */ public static List> project(Object iterable, Converter>... projectors) { return convert(iterable, new ProjectConverter(projectors)); } /** * Creates a converter that projects the value of the argument of an object using as alias * the argument property name as defined by {@link Argument#getInkvokedPropertyName()} * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A converter that can be used as projector in the {@link Lambda#project(Object, Converter[])} method */ public static Converter> as(Object argument) { return new AliasedArgumentConverter(argument); } /** * Creates a converter that projects the value of the argument of an object using as the given alias * @param alias The key on which the argument value is paired * @param argument An argument defined using the {@link Lambda#on(Class)} method * @return A converter that can be used as projector in the {@link Lambda#project(Object, Converter[])} method */ public static Converter> as(String alias, Object argument) { return new AliasedArgumentConverter(alias, argument); } // //////////////////////////////////////////////////////////////////////// // /// Matcher // //////////////////////////////////////////////////////////////////////// /** * Creates an hamcrest matcher that is evalued to true accordingly to the value of the passed argument * @param argument The boolean argument defined using the {@link Lambda#on(Class)} method that has to be matched * @return The hamcrest matcher that is evalued to true accordingly to the value of the passed argument */ public static HasArgumentWithValue having(Boolean argument) { return havingValue(argument); } /** * Creates an hamcrest matcher that is evalued to true if the value of the given argument satisfies * the condition defined by the passed matcher. * @param argument The argument defined using the {@link Lambda#on(Class)} method that has to be matched * @param matcher The matcher against which the value of the given argument has to be compared * @return The hamcrest matcher that is evalued to true if the value of the passed argument matches the given matcher */ public static HasArgumentWithValue having(A argument, Matcher matcher) { return havingValue(argument, matcher); } // //////////////////////////////////////////////////////////////////////// // /// Closure // //////////////////////////////////////////////////////////////////////// /** * Binds an object to the active closure that is the last one created in the current thread. * @param closed The object that has to be bind to the active closure * @return A proxy of the same class of the passed object used to register all the invocation on the closed object */ public static T of(T closed) { return of(closed, (Class)closed.getClass()); } /** * Binds an object to the active closure that is the last one created in the current thread. * @param closed The object that has to be bind to the active closure * @param closedClass The actual class of the proxied object * @return An instance of the closedClass that is actually a proxy used to register all the invocation on the closed object */ public static T of(T closed, Class closedClass) { return bindClosure(closed, closedClass); } /** * Defines a free variable of the given Class for the currently active closure * @param clazz The Class of the new argument * @return A placeholder that represent a free closure variable of the given Class */ public static T var(Class clazz) { return createClosureVarPlaceholder(clazz); } /** * Creates a generic (not typed) closure and binds it to the current thread * @return The newly created closure */ public static Closure closure() { return createClosure(); } /** * Creates a closure with a single free variable and binds it to the current thread * @param type1 The type of the free parameter of the newly created closure * @return The newly created closure */ public static Closure1 closure(Class type1) { return createClosure(type1); } /** * Creates a closure with two free variables and binds it to the current thread * @param type1 The type of the first free variable of the newly created closure * @param type2 The type of the second free variable of the newly created closure * @return The newly created closure */ public static Closure2 closure(Class type1, Class type2) { return createClosure(type1, type2); } /** * Creates a closure with three free variables and binds it to the current thread * @param type1 The type of the first free variable of the newly created closure * @param type2 The type of the second free variable of the newly created closure * @param type3 The type of the third free variable of the newly created closure * @return The newly created closure */ public static Closure3 closure(Class type1, Class type2, Class type3) { return createClosure(type1, type2, type3); } /** * Creates a closure with four free variables and binds it to the current thread * @param type1 The type of the first free variable of the newly created closure * @param type2 The type of the second free variable of the newly created closure * @param type3 The type of the third free variable of the newly created closure * @param type4 The type of the fourth free variable of the newly created closure * @return The newly created closure */ public static Closure4 closure(Class type1, Class type2, Class type3, Class type4) { return createClosure(type1, type2, type3, type4); } /** * Returns the result of the invocation of the method that uses the given delayed closure * @param delayedClosure The closure defined through the {@link DelayedClosure} syntax * @return The result of the invocation of the method that uses the given delayed closure */ public static ClosureResult delayedClosure(DelayedClosure delayedClosure) { return delayedClosure.getClosureResult(); } }