Eachっていうクラス書いてみた

javaでよく、

```java:before
BigDecimal result= BigDecimal.ZERO;

for(BigDecimal elm : collection_of_BigDecimal){
    if(elm != null){
        result= result.add(elm);
    }
}
```

↑のようなコードを書くのだけど、なんかうまくないなぁと思ってた。
で、↓のようなクラス書いてみた。

```java: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;
}
```

これで↓のように書ける。

```java: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が入る可能性があるなら、こんな感じ。

```java: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);
```

```java: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);
```

まだテストあんまりしてないから、バグあるかも。