Nova versão do projeto disponivel para download(ver pagina Towel Project), os tutoriais explicados aqui também estão na Wiki do projeto.
A classe CollectionsUtil tem alguns métodos novos que é algo que estou desenvolvendo para depois usar em outra parte do projeto, mas já é bem util.
CollectionsUtil.split(List l, String field)
Esse método retorna uma List com os valores do atributo ‘field’ que estão em cada objeto da lista ‘l’.
Por exemplo, usando o modelo Person
public class Person {
private String name;
private int age;
public Person(String str, double d) {
this.name = str;
this.age = (int) d;
}
}
Se tivermos uma Lista de Person e quisermos uma lista com todas as idades, é possivel fazer o seguinte.
List<Person> list = new ArrayList<Person>();
list.add(new Person("A", 10.0));
list.add(new Person("B", 20.0));
list.add(new Person("C", 30.0));
list.add(new Person("D", 40.0));
list.add(new Person("E", 50.0));
List<Double> ages = CollectionsUtil.split(list, "age");
E ‘ages’ terá os elementos [10.0,20.0,30.0,40.0,50.0].
Mas o mais interessante com isso, é a novo package collections.aggr.
Ela permite aplicar uma função sobre todos os elementos de uma lista e obter o resultado. Funções como, soma, média ou qualquer coisa de acordo com a implementação de AggregateFunction.
Para usa-la é simples:
List<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);
Integer sum = CollectionsUtil.aggregate(new FuncSum(), list).intValue();//.intValue por que FuncSum retorna Number
Double avg = CollectionsUtil.aggregate(new FuncAvg(), list).doubleValue();
System.out.println("sum = " + sum);
System.out.println("avg = " + avg);
As classes FuncSum(Soma) e FuncAvg(Média) já estão implementadas no projeto e existe uma terceira, FuncConcat que concatena Strings.
Também é possivel aplicar sobre uma coleção de objetos diferentes do que a Func espera, para isso, usar o método.
CollectionsUtil.aggregate(List l, AggregateFunc func, String field)
Que o resultado será a função aplicada sobre todos os objetos resultantes de CollectionsUtil.split(l, field).
Sobre a AggregateFunction, para criar novas implementações de funções, criar uma implementação dessa classe, sua assinatura é:
package com.towel.collections.aggr;
/**
* Functions to work over an object, the object is of the type T
*
* @author marcos.vasconcelos
*/
public interface AggregateFunc<T> {
/**
* Init this Func with the initial values.
* This method is called when a new Calculation over a Collection is going to ve initiated.
* When implementing, reset all values to it initial value.
*/
public void init();
/**
* Called over each value in a List.
* This method should calculate the new value with a previous value.
* @param obj
*/
public void update(T obj);
/**
* Called when the iteration is over and the final value is done.
* @return The value of the function apllied over all objects passed in Func.update
*/
public T getResult();
}
O método init é chamado antes das iterações.
O método update é chamado com cada objeto que a função trabalha.
O método getResult é chamado depois das iterações, e deve retornar o resultado do processo.
Como exemplo, essa é a implementação para média.
package com.towel.collections.aggr;
public class FuncAvg implements AggregateFunc<Number>{
private Number x;
private int total;
@Override
public void update(Number obj) {
x = new Double(x.doubleValue() + obj.doubleValue());
total++;
}
@Override
public Number getResult() {
return x.doubleValue() / total;
}
@Override
public void init() {
x = new Double(0);
total = 0;
}
}
Se alguém criar uma AggregateFunction interessante e quiser coloca-la no projeto é só me enviar.