Skip to content

Instantly share code, notes, and snippets.

@ponkotuy
Last active December 17, 2015 23:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ponkotuy/5690470 to your computer and use it in GitHub Desktop.
Save ponkotuy/5690470 to your computer and use it in GitHub Desktop.
Java8のサンプル
package com.ponkotuy;
import java.util.function.Consumer;
/**
* Created with IntelliJ IDEA.
* User: yosuke
* Date: 13/05/31
* Time: 3:23
* 実装付きinterface
* Lambda式で代入されたメソッドはapplyImplをoverrideする
* _はacceptのショートカット
*/
@FunctionalInterface
public interface C<T> extends Consumer<T> {
public default void accept(T a) {
try {
applyImpl(a);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void applyImpl(T a) throws Exception;
public default void _(T a) {
accept(a);
}
}
package com.ponkotuy;
import java.util.function.Consumer;
/**
* Created with IntelliJ IDEA.
* User: yosuke
* Date: 13/05/31
* Time: 2:42
* To change this template use File | Settings | File Templates.
*/
@FunctionalInterface
public interface C0 extends Consumer<Object> {
public default void accept(Object a) {
try {
applyImpl();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public default void _() { accept(null); }
public void applyImpl() throws Exception;
}
package com.ponkotuy;
import java.util.function.Function;
/**
* Created with IntelliJ IDEA.
* User: yosuke
* Date: 13/05/31
* Time: 3:06
* To change this template use File | Settings | File Templates.
*/
@FunctionalInterface
public interface F<A, B> extends Function<A, B> {
public default B apply(A a) {
try {
return applyImpl(a);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public B applyImpl(A a) throws Exception;
public default B _(A a) { return apply(a); }
}
package com.ponkotuy;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Created with IntelliJ IDEA.
* User: yosuke
* Date: 13/05/30
* Time: 22:12
* To change this template use File | Settings | File Templates.
*/
public class Lambda {
// SimpleなLambda式(Function)の例
// Method名はapply
public static void simpleFunction() {
Function<Integer, Integer> succ = x -> x + 1;
assert succ.apply(1) == 2;
}
// 2引数のLambda式は(x, y) ->で記述
// reduceメソッドなどで、BinaryOperatorのように型が限定された2引数関数が使われる
// Tupleでは無いし、Java8でTupleはそもそも実装されていない
public static void simpleFunction2() {
BiFunction<Integer, Integer, Integer> add = (i, j) -> i + j;
BinaryOperator<Integer> boAdd = (i, j) -> i + j; // (T, T) -> Tに限定されたBiFunction
assert add.apply(1, 2) == 3;
assert boAdd.apply(1, 2) == 3;
}
// SimpleなLambda式(Consumer)の例
// Method名はaccept
public static void simpleConsumer() {
Consumer<Integer> pInt = x -> System.out.println(x);
pInt.accept(100);
}
// Primitive型を取るConsumer
public static void simpleConsumer2() {
IntConsumer pInt = x -> System.out.println(x);
pInt.accept(100);
}
// 引数を取らない関数
// Syntaxだけでは内部に状態持てないので使い道はあまり思い付かない
// Method名はget
public static void simpleSupplier() {
Supplier<Integer> one = () -> 1;
assert one.get() == 1;
}
// Booleanを返すFunction
// Method名はtest
// 2引数のBiPredicateもある
public static void simplePrediate() {
Predicate<Integer> isEven = x -> x % 2 == 0;
assert isEven.test(2);
}
// forEachのサポート
// Iterable Interfaceに実装されている
public static void simpleForEach() {
List<String> strings = Arrays.asList("b", "cd", "abe");
strings.forEach(System.out::println); // メソッド参照で直接メソッドを渡せる
// strings.map(...); mapは無いのでFunctionは渡せない。残念!
}
// Functionを渡すsort
// Lambda式において、Javaで初めて型推論がサポートされた
public static void listLambda() {
List<String> strings = Arrays.asList("ade", "b", "cd");
strings.stream() // 便利メソッドはListではなくStream型にあるので変換
.sorted((x, y) -> x.length() - y.length()) // もちろん非破壊sort
.map(x -> x.length() + ": " + x) // mapもできる
.forEach(System.out::println); // もちろんforEachできる
}
public static void main(String[] args) {
C0 pl = () -> System.out.println();
simpleFunction();
simpleFunction2();
simpleConsumer2();
simpleSupplier();
simplePrediate();
pl._(); // _呼び出し便利だけど「将来的にサポートされないかも」というwarningが出る
simpleForEach();
pl._();
listLambda();
}
}
package com.ponkotuy;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Created with IntelliJ IDEA.
* User: yosuke
* Date: 13/06/06
* Time: 3:03
* To change this template use File | Settings | File Templates.
*/
public class StreamSample {
// collectのサンプル
public static void collectSample() {
Stream<String> stream = Stream.of("abc", "d", "ef", "ghi");
// collectとtoStringJoinerでStreamを結合処理して返す
// StringJoiner型を返すので遅延評価しているかもと思ったが、そうではなく、
// 内部ではStringJoinerというmutableなオブジェクトへの追記で実装しているので、必然的にStringJoinerが返る
StringJoiner joiner = stream.collect(Collectors.toStringJoiner(", "));
assert joiner.toString().equals("abc, d, ef, ghi");
// Lengthの値をKeyに、その値を集めたListをValueにしたMap生成する
// ScalaのgroupByっぽい挙動
// Valueは必ずListになっている。Streamが欲しいこともあろうに…
Map<Integer, List<String>> group = stream.collect(Collectors.groupingBy(String::length));
assert group.get(3).equals(Arrays.asList("abc", "ghi"));
}
public static void sampleCollector() {
List<Integer> list = new ArrayList<>();
for(int i = 0; i<=10000; ++i) { list.add(i); }
// Collectorを自作する
// Collectorは内部で状態を変更しながらCollectionを入力したりもできるreduce
System.out.println("MySumCollector");
Util.execTime(1000, (C0) () -> {
int result = list.stream().collect(MySumCollector._());
assert result == 50005000 : result;
});
// sumを取るCollectorは既に実装が存在する
// ただしLongで実装されていて浮動小数点とかIntegerは面倒
System.out.println("Collectors.sumBy");
Util.execTime(1000, (C0) () -> {
long result = list.stream().collect(Collectors.sumBy(it -> it.longValue()));
assert result == 50005000 : result;
});
// sumByはreducing使って実装されている
System.out.println("Collectors.reducing");
Util.execTime(1000, (C0) () -> {
int result = list.stream().collect(Collectors.reducing(0, Integer::sum));
assert result == 50005000 : result;
});
// 実際問題reduceの方が早いとか言わないお約束(処理速度も早い)
System.out.println("reduce");
Util.execTime(1000, (C0) () -> {
int result = list.stream().reduce(0, Integer::sum);
assert result == 50005000 : result;
});
// 並列の場合
// Combinerが呼ばれるようになる
System.out.println("Parallel MySumCollector");
Util.execTime(1000, (C0) () -> {
int result = list.parallelStream().collect(MySumCollector._());
assert result == 50005000 : result;
});
}
// Integerの合計値を計算するCollector
// 勿論これはSampleで、単に合計したいだけならsumByやreduceを使うべき
public static class MySumCollector implements Collector<Integer, Integer> {
public static MySumCollector apply() {
return new MySumCollector();
}
public static MySumCollector _() {
return MySumCollector.apply();
}
// 初期値。CollectにCollectionなどを使う場合はここで初期化する必要がある。
@Override
public Supplier<Integer> resultSupplier() {
return () -> 0;
}
// 一般的なreduceと同じく、途中経過と新しい値を受け取り、結果を生成する
@Override
public BiFunction<Integer, Integer, Integer> accumulator() {
return Integer::sum;
}
// 途中経過と途中経過を受け取り、結果を生成する
// streamでは基本呼ばれないが、parallelStreamで並列化に使われる
@Override
public BinaryOperator<Integer> combiner() {
return (x, y) -> {
// System.out.println(String.format("call combiner: (%d, %d)", x, y));
return Integer.sum(x, y);
};
}
// このCollectorがどのような場合に適用可能か設定する
// immutableなSetを渡す必要がある
@Override
public Set<Collector.Characteristics> characteristics() {
return Collections.unmodifiableSet(
EnumSet.of(
// Characteristics.CONCURRENT, // 並列実行可能
// Characteristics.STRICTLY_MUTATIVE, // accumulatorとcombinerが常に第1引数の状態を変更した結果を返す
Characteristics.UNORDERED // Setのような順番が無いものに対して適用可能か
)
);
}
}
// 並列コレクションのサンプル。parallelStream()を呼び出すことで、処理が並列化できる
// Function内では明示的な例外を投げることができないので、中で潰す必要がある
public static void parallelCollection1() {
List<Integer> list = Arrays.asList(1, 2, 3);
list.parallelStream().forEach(x -> {
try {
Thread.sleep(x * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 自作のinterfaceにLambdaを突っ込むことができる。
// 明示例外を中で非明示例外に変換している
public static void parallelCollection2() {
List<Integer> list = Arrays.asList(1, 2, 3);
C<Integer> sleep = x -> Thread.sleep(x * 1000);
list.parallelStream().forEach(sleep);
}
// キャストでも良い
public static void parallelCollection3() {
List<Integer> list = Arrays.asList(1, 2, 3);
list.parallelStream().forEach((C<Integer>) x -> Thread.sleep(x * 1000));
}
public static void main(String[] args) {
sampleCollector();
C0 sub = () -> parallelCollection3();
Util.execTime(sub);
}
}
package com.ponkotuy;
import java.util.function.Consumer;
/**
* Created with IntelliJ IDEA.
* User: yosuke
* Date: 13/06/06
* Time: 3:22
* To change this template use File | Settings | File Templates.
*/
public class Util {
// 無名関数を引数に取る関数
// 関数の実行時間を計測する
public static void execTime(int count, Consumer f) {
long now = System.currentTimeMillis();
for (int i = 0; i < count; ++i) {
f.accept(null);
}
long diff = System.currentTimeMillis() - now;
System.out.println(diff / 1000.0 + "s");
}
public static void execTime(Consumer f) {
execTime(1, f);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment