覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

streamsupportはStream操作以外にも色々提供してくれる

streamsupportは基本的にJavaのStream APIを代替する機能を提供してくれますが、それに留まらずStream API以外のJava8の機能やJava9で追加される機能もバックポートしています。
それら機能について以下紹介していきます。

以下内容については、Mavenを利用することを前提にしています。
また、サンプルはRetrolambdaを組み合わせることを前提にした(ラムダ式を利用した)コードを一部記述しています


streamsupport-atomic

Java標準のjava.util.concurrent.atomicパッケージに対応する機能群の一部をjava8.util.concurrent.atomicで提供します。

streamsupport-atomicを利用する場合はpom.xmlに以下を追記します。

<dependency>
    <groupId>net.sourceforge.streamsupport</groupId>
    <artifactId>streamsupport-atomic</artifactId>
    <version>1.5.2</version>
</dependency>

■提供されるクラス群

java8.util.concurrent.atomicパッケージで以下のクラス群が提供されます

  • LongAdder
  • LongAccumulator
  • DoubleAdder
  • DoubleAccumulator

■サンプルコード

import java8.util.concurrent.atomic.LongAdder;

long[] longArray1 = { 10, 20, 30, 40, 50 };
long[] longArray2 = { 1, 2, 3, 4, 5 };

LongAdder adder = new LongAdder();
LongAdder totalCount = new LongAdder();

for (long value : longArray1) {
    adder.add(value);
    totalCount.increment();
}

System.out.println("(1) elements count=" + totalCount.sum() + ", sum=" + adder.sum());

adder.reset();

for (long value : longArray2) {
    adder.add(value);
    totalCount.increment();
}

System.out.println("(2) elements count=" + totalCount.sum() + ", sum=" + adder.sum());

■実行結果

(1) elements count=5, sum=150
(2) elements count=10, sum=15


streamsupport-cfuture

CompletableFuture APIを提供します。

streamsupport-cfutureを利用する場合はpom.xmlに以下を追記します。

<dependency>
    <groupId>net.sourceforge.streamsupport</groupId>
    <artifactId>streamsupport-cfuture</artifactId>
    <version>1.5.2</version>
</dependency>

■提供されるクラス群

java8.util.concurrentパッケージで以下のクラス群が提供されます

  • CompletableFuture
  • CompletionStage

■サンプルコード

あまりいいサンプルコードが書けなかったのでサンプルは省略します(笑)

Java8のjava.util.concurrent.CompletableFuturejava.util.concurrent.CompletionStageに対応したものが提供されます。


streamsupport-literal

Java9で追加予定のJEP 269: Convenience Factory Methods for Collectionsに関するコレクションの生成ファクトリを提供します。

streamsupport-literalを利用する場合はpom.xmlに以下を追記します。

<dependency>
    <groupId>net.sourceforge.streamsupport</groupId>
    <artifactId>streamsupport-literal</artifactId>
    <version>1.5.2</version>
</dependency>

■提供されるクラス群

java8.utilパッケージで以下のクラス群が提供されます(なぜパッケージ名がjava8なのかはよく分かりません)

  • Lists2
  • Maps2
  • Sets2


■(1)サンプルコード(Listの生成)

import java.util.List;
import java8.util.Lists2;


List<String> list0 = Lists2.of();

List<String> list1 = Lists2.of("value1");

List<String> list2 = Lists2.of("value1", "value2");

List<String> list5 = Lists2.of("value1", "value2", "value3", "value4", "value5");


System.out.println("list0 => " + list0.getClass() + " : size=" + list0.size() + " : " + list0);
System.out.println("list1 => " + list1.getClass() + " : size=" + list1.size() + " : " + list1);
System.out.println("list2 => " + list2.getClass() + " : size=" + list2.size() + " : " + list2);
System.out.println("list5 => " + list5.getClass() + " : size=" + list5.size() + " : " + list5);


System.out.println("-------------------------------");

// ImmutableなListが生成されているのでaddしようとすると例外が起きる
try {
     list2.add("value3");
} catch (Exception e) {
     e.printStackTrace();
}

■(1)実行結果

list0 => class java8.util.ImmutableCollections$List0 : size=0 : []
list1 => class java8.util.ImmutableCollections$List1 : size=1 : [value1]
list2 => class java8.util.ImmutableCollections$List2 : size=2 : [value1, value2]
list5 => class java8.util.ImmutableCollections$ListN : size=5 : [value1, value2, value3, value4, value5]
-------------------------------
java.lang.UnsupportedOperationException
    at java8.util.ImmutableCollections.uoe(ImmutableCollections.java:75)
    at java8.util.ImmutableCollections$AbstractImmutableList.add(ImmutableCollections.java:81)
    at sample.ss.stream.ss.other.Lists2Sample.main(Lists2Sample.java:29)


■(2)サンプルコード(Mapの生成)

import java.util.Map;
import java8.util.Maps2;


Map<Integer, String> map0 = Maps2.of();

Map<Integer, String> map1 = Maps2.of(1, "value1");

Map<Integer, String> map2 = Maps2.of(10, "value1", 20, "value2");

Map<Integer, String> map3 = Maps2.of(101, "value1", 102, "value2", 103, "value3");


System.out.println("map0 => " + map0.getClass() + " : size=" + map0.size() + " : " + map0);
System.out.println("map1 => " + map1.getClass() + " : size=" + map1.size() + " : " + map1);
System.out.println("map2 => " + map2.getClass() + " : size=" + map2.size() + " : " + map2);
System.out.println("map3 => " + map3.getClass() + " : size=" + map3.size() + " : " + map3);


System.out.println("-------------------------------");

// ImmutableなMapが生成されているのでaddしようとすると例外が起きる
try {
     map2.put(30, "value3");
} catch (Exception e) {
     e.printStackTrace();
}

■(2)実行結果

map0 => class java8.util.ImmutableCollections$Map0 : size=0 : {}
map1 => class java8.util.ImmutableCollections$Map1 : size=1 : {1=value1}
map2 => class java8.util.ImmutableCollections$MapN : size=2 : {20=value2, 10=value1}
map3 => class java8.util.ImmutableCollections$MapN : size=3 : {101=value1, 103=value3, 102=value2}
-------------------------------
java.lang.UnsupportedOperationException
    at java8.util.ImmutableCollections.uoe(ImmutableCollections.java:75)
    at java8.util.ImmutableCollections$AbstractImmutableMap.put(ImmutableCollections.java:443)
    at sample.ss.stream.ss.other.Maps2Sample.main(Maps2Sample.java:29)


streamsupport-flow

JDK 9 Flow API(Java 9で導入される予定のReactive Streams向けのpublish-subscribeフレームワーク)を提供してくれます
JEP 266: More Concurrency Updates

streamsupport-flowを利用する場合はpom.xmlに以下を追記します。

<dependency>
    <groupId>net.sourceforge.streamsupport</groupId>
    <artifactId>streamsupport-flow</artifactId>
    <version>1.5.2</version>
</dependency>

■提供されるクラス群

java8.util.concurrentパッケージで以下のクラス群が提供されます(なぜパッケージ名がjava8なのかはよく分かりません)

  • Flow
  • Flow.Publisher
  • Flow.Subscriber
  • Flow.Subscription
  • Flow.Processor
  • SubmissionPublisher

■サンプルコード

import java8.util.concurrent.Flow.Subscriber;
import java8.util.concurrent.Flow.Subscription;
import java8.util.concurrent.SubmissionPublisher;
import java8.util.stream.RefStreams;

public class FlowSample {

    public static void main(String[] args) {
        SubmissionPublisher<String> publisher = new SubmissionPublisher<>();

        //Subscriberの登録
        SimpleSubscriber<String> subscriber = new SimpleSubscriber<>();
        publisher.subscribe(subscriber);

        //値の発行
        System.out.println("Publishing Items...");

        RefStreams.of("1", "###", "2", "###", "3", "###", "4", "###")
            .forEach(e -> publisher.submit(e));

        publisher.close();
    }

    static final class SimpleSubscriber<T> implements Subscriber<T> {

        private Subscription subscription;

        @Override
        public void onSubscribe(Subscription subscription) {
            this.subscription = subscription;
            subscription.request(1);
        }

        @Override
        public void onNext(T item) {
            System.out.println("> OnNext : " + item);
            subscription.request(1);
        }

        @Override
        public void onError(Throwable t) {
            System.out.println("On Error: " + t.getMessage());
        }

        @Override
        public void onComplete() {
            System.out.println("Complete!!");
        }
    }
}

■実行結果

Publishing Items...
> OnNext : 1
> OnNext : ###
> OnNext : 2
> OnNext : ###
> OnNext : 3
> OnNext : ###
> OnNext : 4
> OnNext : ###
Complete!!


まとめ

streamsupportはStream APIにとどまらず、Java9の機能にまで及ぶ範囲でバックポートをしてくれていることが分かりました。



関連エントリ