javaでよく、
before
BigDecimal result= BigDecimal.ZERO;
for(BigDecimal elm : collection_of_BigDecimal){
if(elm != null){
result= result.add(elm);
}
}
↑のようなコードを書くのだけど、なんかうまくないなぁと思ってた。
で、↓のようなクラス書いてみた。
jp.michikusa.chitose.util.math.Each
package jp.michikusa.chitose.util.math;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.List;
import com.google.common.collect.Lists;
public class Each<E, R>{
public static interface Operator<E, R>{
R apply(R a, E b);
}
public static <E, R>Each<E, R> of(Operator<? super E, R> op){
return new Each<>(op, null);
}
public Each<E, R> skipNulls(){
return new SkipNulls<>(this);
}
public Each<E, R> useForNull(E null_value){
return new UseForNull<E, R>(this, null_value);
}
public final Each<E, R> startWith(R start_with){
return this.newEach(this.op, start_with);
}
public final R applyTo(Collection<? extends E> elms){
List<E> working= Lists.newArrayList(elms);
R result= this.start_with;
for(E elm : working){
result= this.apply(result, elm);
}
return result;
}
protected R apply(R result, E elm){
return this.op.apply(result, elm);
}
protected Each<E, R> newEach(Operator<? super E, R> op, R start_with){
return new Each<>(op, start_with);
}
private static class UseForNull<E, R> extends Each<E, R>{
public UseForNull(Each<? super E, R> prototype, E null_value){
super(prototype.op, prototype.start_with);
this.null_value= checkNotNull(null_value);
}
@Override
public Each<E, R> useForNull(E null_value){
throw new UnsupportedOperationException();
}
@Override
public Each<E, R> skipNulls(){
throw new UnsupportedOperationException();
}
@Override
protected R apply(R result, E elm){
return super.apply(result, this.get(elm));
}
@Override
protected Each<E, R> newEach(Operator<? super E, R> op, R start_with){
return new UseForNull<>(new Each<>(op, start_with), this.null_value);
}
private E get(E origin){
if(origin == null){ return this.null_value; }
return origin;
}
private final E null_value;
}
private static class SkipNulls<E, R> extends Each<E, R>{
public SkipNulls(Each<E, R> prototype){
super(prototype.op, prototype.start_with);
}
@Override
public Each<E, R> skipNulls(){
throw new UnsupportedOperationException();
}
@Override
public Each<E, R> useForNull(E null_value){
throw new UnsupportedOperationException();
}
@Override
protected R apply(R result, E elm){
if(elm == null){ return result; }
return super.apply(result, elm);
}
@Override
protected Each<E, R> newEach(Operator<? super E, R> op, R start_with){
return new SkipNulls<>(this);
}
}
private Each(Operator<? super E, R> op, R start_with){
checkNotNull(op);
this.op= op;
this.start_with= start_with;
}
private final Operator<? super E, R> op;
private final R start_with;
}
これで↓のように書ける。
after
List<Integer> elms= Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Integer result= Each.of(new Operator<Integer, Integer>(){
@Override
public Integer apply(Integer a, Integer b){
return a + b;
}
}).startWith(0).applyTo(elms);
assertEquals(Integer.valueOf(36), result);
要素としてnullが入る可能性があるなら、こんな感じ。
nullable0
List<Integer> elms= Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Integer result= Each.of(new Operator<Integer, Integer>(){
@Override
public Integer apply(Integer a, Integer b){
return a + b;
}
}).startWith(0).useForNull(0).applyTo(elms);
assertEquals(Integer.valueOf(36), result);
nullable1
List<Integer> elms= Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Integer result= Each.of(new Operator<Integer, Integer>(){
@Override
public Integer apply(Integer a, Integer b){
return a + b;
}
}).startWith(0).skipNulls().applyTo(elms);
assertEquals(Integer.valueOf(36), result);
まだテストあんまりしてないから、バグあるかも。