Stream の forEach や、map 、filter 、様々なラムダ式実行の中で、カウンタが必要な時、
しかたなく、AtomicInteger や、グローバルスコープに置いたカウンタインクリメント参照を
よく書いてました。
また、ネット検索してよく紹介されてる例は、実行処理記述で関数型インターフェース定義を書き直す
方法で、以下のような書き方です。
Stream.iterate('A', e->(char)(e+1)).limit(8) .forEach(new Consumer<Character>(){ int c = 1; @Override public void accept(Character t){ System.out.println(c + ":" + t); c++; } });
これだと、t->{ } というラムダ式記述ではなくなって、
関数型インターフェース使用の旨味がなくなってしまいます。
それでは、、、
BiConsumer で書いて、Consumer を返す static メソッドを用意する方法
public static <T> Consumer<T> countCounsumer(BiConsumer<T, Long> biconsumer){ AtomicLong c = new AtomicLong(1); return t->{ biconsumer.accept(t, c.getAndIncrement()); }; }
以下のように書くことができます。
Stream.iterate('A', e->(char)(e+1)).limit(8) .forEach(countCounsumer((t, i)->{ System.out.println(i + ":" + t); }));
static メソッドを都度々、書くのをさけるなら、Consumer を 継承して、、
import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiConsumer; import java.util.function.Consumer; /** * CountCounsumer */ public interface CountCounsumer<T> extends Consumer<T>{ public static <T> Consumer<T> of(BiConsumer<T, Long> biconsumer){ AtomicLong c = new AtomicLong(1); return t->{ biconsumer.accept(t, c.getAndIncrement()); }; } }
この方が汎用性もあります。
Stream.iterate('A', e->(char)(e+1)).limit(8) .forEach(CountCounsumer.of((t, i)->{ System.out.println(i + ":" + t); }));
Stream でカウンタが欲しいのは、forEach だけではないはずで、
例えば、filter ~ Predicate だって、欲しいこともあります。
上と同じように、、static メソッドなら、、
public static <T> Predicate<T> countPredicate(BiPredicate<T, Long> bipredicate){ AtomicLong c = new AtomicLong(1); return t->{ return bipredicate.test(t, c.getAndIncrement()); }; }
例)
Stream.iterate('A', e->(char)(e+1)).limit(8) .filter(countPredicate((e, i)->i % 2 == 1)) .forEach(CountCounsumer.of((t, i)->{ System.out.println(i + ":" + t); }));
Predicate を継承して、、
import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiPredicate; import java.util.function.Predicate; /** * CountPredicate */ public interface CountPredicate<T> extends Predicate<T>{ public static <T> Predicate<T> of(BiPredicate<T, Long> bipredicate){ AtomicLong c = new AtomicLong(1); return t->{ return bipredicate.test(t, c.getAndIncrement()); }; } }
例)
Stream.iterate('A', e->(char)(e+1)).limit(8) .filter(CountPredicate.of((e, i)->i % 2 == 1)) .forEach(CountCounsumer.of((t, i)->{ System.out.println(i + ":" + t); }));