Last active
December 17, 2015 23:39
-
-
Save ponkotuy/5690470 to your computer and use it in GitHub Desktop.
Java8のサンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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