もっと Lambda その4

正式版のリリースが2014年3月18日に延期された Java8 の Lambda を今回も楽しんでみます。

いつものようにネットから情報を取得して少しコードを変えて動かしているだけの写経のようなことをやってます。

詳しいことは解らないけど慣れるってことが目的です!

今回はデザインパターンの一つである Template Method Pattern を Lambda を使って実装してみる試みです。

Template Method Pattern について知りたければグーグル先生に聞いてみたらいっぱい答えを教えてくれます。

Wikipedia では、Template Method パターン(テンプレート・メソッド・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。

「振る舞いに関するパターン」に属する。Template Method パターンの目的は、ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、

そのアルゴリズムの具体的な設計をサブクラスに任せることである。

そのため、システムのフレームワークを構築するための手段としてよく活用される。

と記載されてます。

今回のサンプルは現在の日付とそれぞれ30日後、60日後の日付を表示させ、ついでにつまらないメッセージも表示させるだけです。

それでは Lambda を使わないプログラムです。(Java8 の新機能の Date and Time API は使ってます。)

package jp.yucchi.oldtemplatemethodpattern;

import java.time.LocalDate;

abstract class DateCalc {

    void getNowDate() {
        System.out.println("今日は " + LocalDate.now() + " です。");
    }

    protected abstract void getTargetDate();

    void saySorry() {
        System.out.println("ワイルドだろぅ ごめんね。こんなサンプルで (ノД`)\n");
    }
}

package jp.yucchi.oldtemplatemethodpattern;

import java.time.LocalDate;

class DateCalcImpl_1 extends DateCalc {

    @Override
    protected void getTargetDate() {
        System.out.println("30日後は" + LocalDate.now().plusDays(30) + " です。");
    }
}
package jp.yucchi.oldtemplatemethodpattern;

import java.time.LocalDate;

class DateCalcImpl_2 extends DateCalc {

    @Override
    protected void getTargetDate() {
        System.out.println("60日後は" + LocalDate.now().plusDays(60) + " です。");
    }
}

 

package jp.yucchi.oldtemplatemethodpattern;

public class OldTemplateMethodPattern {

    public static void main(String[] args) {
        printTargetDate(new DateCalcImpl_1());
        printTargetDate(new DateCalcImpl_2());
    }

    private static void printTargetDate(DateCalcImpl_1 dateCalcImpl_1) {
        dateCalcImpl_1.getNowDate();
        dateCalcImpl_1.getTargetDate();
        dateCalcImpl_1.saySorry();
    }

    private static void printTargetDate(DateCalcImpl_2 dateCalcImpl_2) {
        dateCalcImpl_2.getNowDate();
        dateCalcImpl_2.getTargetDate();
        dateCalcImpl_2.saySorry();
    }
}

実行結果は次のようになります。

今日は 2013-04-30 です。
30日後は2013-05-30 です。
ワイルドだろぅ ごめんね。こんなサンプルで (ノД`)

今日は 2013-04-30 です。
60日後は2013-06-29 です。
ワイルドだろぅ ごめんね。こんなサンプルで (ノД`)

当然の結果で何も問題ないですね。

実際にはこのような実装は無いかと思いますが一応 Template Method Pattern の定義に沿っているのでよしとしてください。

それではこのコードを Java8 の Lambda を使うとどうなるか?

こんなになりました~! (*^o^*)

package jp.yucchi.templatemethodpattern4lambda;

import java.time.LocalDate;

@FunctionalInterface
public interface DateInterface {

    default void getNowDate() {
        System.out.println("今日は " + LocalDate.now() + " です。");
    }

    void getTargetDate();

    default void saySorry() {
        System.out.println("ワイルドだろぅ ごめんね。こんなサンプルで (ノД`)\n");
    }
}

 

package jp.yucchi.templatemethodpattern4lambda;

import java.time.LocalDate;

public class TemplateMethodPattern4Lambda {

    public static void main(String[] args) {
        printTargetDate(() -> System.out.println("30日後は" + LocalDate.now().plusDays(30) + " です。"));
        printTargetDate(() -> System.out.println("60日後は" + LocalDate.now().plusDays(60) + " です。"));
    }

    private static void printTargetDate(DateInterface dateInterface) {
        dateInterface.getNowDate();
        dateInterface.getTargetDate();
        dateInterface.saySorry();
    }

}

実行結果は次のようになります。

今日は 2013-04-30 です。
30日後は2013-05-30 です。
ワイルドだろぅ ごめんね。こんなサンプルで (ノД`)

今日は 2013-04-30 です。
60日後は2013-06-29 です。
ワイルドだろぅ ごめんね。こんなサンプルで (ノД`)

こちらも当然の結果で何も問題ないですね。

Lambda を使うと本当にシンプルになります。

「抽象クラスを使ってないじゃないか!」って怒らないでね。(^_^;)

DateInterface (FunctionalInterface) での Default Methods が使えるのが良いですね。

これって Java で禁じ手の多重継承を可能にするような掟破りの裏技のような気がします。

なかなか面白いですね。(^_^)

それでは、お約束の時間です。

この「もっと Lambda 」シリーズは、インターネット上で得た情報を元にそれを少し変更しているだけです。

悲しいことにその情報源は英語なので詳しい内容はわかりません。

よって私の推測で解釈された内容となってますので間違いがあると思います。

Java8 もまだ build86 を使用していますので API の変更により記述方法が変わるかもしれません。

早く正式リリースされて日本語でこの超便利で素敵な新機能を勉強したい今日この頃です。

cludia_2013_04_30_001

Hatena タグ:

Java8 の Arrays.parallelSort() を試してみた

Java8 では Arrays.parallelSort() が導入される予定だ。

どうやら Fork/Join Framework を使っているようです。

今まではプリミティブ型はデュアルピボットのクイックソートで参照型は Tim ソートだったような記憶があります。

この記憶の信憑性はかなり低いので間違っていても怒らないでくださいね(^_^;)

そこで早速試してみることにします。

コードはシンプルなソートです。

jp\yucchi\parallelsort\ParallelSort.java
package jp.yucchi.parallelsort;

import java.util.Arrays;
import java.util.Date;
import java.util.Random;

public class ParallelSort {

    private static final int TARGET_SIZE = 500_000_000;
    private static final int LOOP_SIZE = 20;
    private static long startTime;
    private static long time;
    private static long avgTime;
    private static long sumTime;
    private static int count;
    private static long avg4p;

    public static void main(String[] args) {
        Random random = new Random(new Date().getTime());
        int[] source = new int[TARGET_SIZE];
        int[] copy;
        for (int i = 0; i < TARGET_SIZE; ++i) {
            source[i] = random.nextInt(TARGET_SIZE);
        }
        for (int i = 0; i < LOOP_SIZE; ++i) {
            copy = Arrays.copyOfRange(source, 0, TARGET_SIZE);
            startTime = System.nanoTime();
            Arrays.parallelSort(copy);
            time = System.nanoTime() - startTime;
            System.out.println(i + 1 + "回目 : Arrays.parallelSortの処理時間は、"
                    + (int) (time * 1e-9) / 3_600 + "時間"
                    + (int) ((time * 1e-9) / 60) % 60 + "分"
                    + (int) (time * 1e-9 % 60) + "秒"
                    + Double.toString((time * 1e-9 % 60) % 1).substring(2) + "\n");
            if (i > 9) {
                sumTime += time;
                count++;
            }
        }
        avgTime = sumTime / count;
        System.out.println("<----- Arrays.parallelSortの平均処理時間は、"
                + (int) (avgTime * 1e-9) / 3_600 + "時間"
                + (int) ((avgTime * 1e-9) / 60) % 60 + "分"
                + (int) (avgTime * 1e-9 % 60) + "秒"
                + Double.toString((avgTime * 1e-9 % 60) % 1).substring(2) + " ----->\n");
        avgTime = 0;
        count = 0;
        sumTime = 0;

        for (int i = 0; i < LOOP_SIZE; ++i) {
            copy = Arrays.copyOfRange(source, 0, TARGET_SIZE);
            startTime = System.nanoTime();
            Arrays.sort(copy);
            time = System.nanoTime() - startTime;
            System.out.println(i + 1 + "回目 : Arrays.sortの処理時間は、"
                    + (int) (time * 1e-9) / 3_600 + "時間"
                    + (int) ((time * 1e-9) / 60) % 60 + "分"
                    + (int) (time * 1e-9 % 60) + "秒"
                    + Double.toString((time * 1e-9 % 60) % 1).substring(2) + "\n");
            if (i > 9) {
                sumTime += time;
                count++;
            }
        }
        avgTime = sumTime / count;
        System.out.println("<----- Arrays.sortの平均処理時間は、"
                + (int) (avgTime * 1e-9) / 3_600 + "時間"
                + (int) ((avgTime * 1e-9) / 60) % 60 + "分"
                + (int) (avgTime * 1e-9 % 60) + "秒"
                + Double.toString((avgTime * 1e-9 % 60) % 1).substring(2) + " ----->\n");

    }

}


全てのソート時間の取得と表示、そして11回目からのソート処理平均時間の取得と表示をそれぞれ

Arrays.parallelSort() と Arrays.sort() で実行してます。

このプログラムの実行結果は概ね予測できますが下記に実行結果を貼っておきます。

1回目 : Arrays.parallelSortの処理時間は、0時間0分4秒4152691810000002

2回目 : Arrays.parallelSortの処理時間は、0時間0分3秒1656751470000004

3回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4398564410000003

4回目 : Arrays.parallelSortの処理時間は、0時間0分3秒18688716800000016

5回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4902016290000004

6回目 : Arrays.parallelSortの処理時間は、0時間0分3秒1557479500000003

7回目 : Arrays.parallelSortの処理時間は、0時間0分3秒5248610990000002

8回目 : Arrays.parallelSortの処理時間は、0時間0分3秒21521467700000008

9回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4352946820000003

10回目 : Arrays.parallelSortの処理時間は、0時間0分3秒176553014

11回目 : Arrays.parallelSortの処理時間は、0時間0分3秒5098383400000004

12回目 : Arrays.parallelSortの処理時間は、0時間0分3秒2292058370000003

13回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4357429300000004

14回目 : Arrays.parallelSortの処理時間は、0時間0分3秒20676435400000015

15回目 : Arrays.parallelSortの処理時間は、0時間0分3秒45285167800000004

16回目 : Arrays.parallelSortの処理時間は、0時間0分3秒2242083810000004

17回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4621416820000004

18回目 : Arrays.parallelSortの処理時間は、0時間0分3秒5754989530000003

19回目 : Arrays.parallelSortの処理時間は、0時間0分3秒500453534

20回目 : Arrays.parallelSortの処理時間は、0時間0分3秒21473901200000034

<—– Arrays.parallelSortの平均処理時間は、0時間0分3秒3811444700000002 —–>

1回目 : Arrays.sortの処理時間は、0時間0分48秒9387049350000041

2回目 : Arrays.sortの処理時間は、0時間0分48秒9633070610000019

3回目 : Arrays.sortの処理時間は、0時間0分49秒015938085000001934

4回目 : Arrays.sortの処理時間は、0時間0分48秒9707528720000056

5回目 : Arrays.sortの処理時間は、0時間0分49秒2902336700000063

6回目 : Arrays.sortの処理時間は、0時間0分48秒9888089870000059

7回目 : Arrays.sortの処理時間は、0時間0分48秒9633770900000016

8回目 : Arrays.sortの処理時間は、0時間0分48秒9997757110000052

9回目 : Arrays.sortの処理時間は、0時間0分48秒9295900030000013

10回目 : Arrays.sortの処理時間は、0時間0分49秒08955452700000421

11回目 : Arrays.sortの処理時間は、0時間0分50秒13118777600000442

12回目 : Arrays.sortの処理時間は、0時間0分49秒8455564950000038

13回目 : Arrays.sortの処理時間は、0時間0分49秒24517728500000402

14回目 : Arrays.sortの処理時間は、0時間0分49秒12246824000000345

15回目 : Arrays.sortの処理時間は、0時間0分48秒901129044000001

16回目 : Arrays.sortの処理時間は、0時間0分49秒40450923900000646

17回目 : Arrays.sortの処理時間は、0時間0分50秒7024559510000046

18回目 : Arrays.sortの処理時間は、0時間0分49秒7857455720000033

19回目 : Arrays.sortの処理時間は、0時間0分50秒1460985550000018

20回目 : Arrays.sortの処理時間は、0時間0分51秒37098508900000127

<—– Arrays.sortの平均処理時間は、0時間0分49秒8655313240000027 —–>

Arrays.parallelSort() が3秒前半のスコアに対して Arrays.sort() は、ほぼ 50 秒かかってます。

予想通り Arrays.parallelSort() が圧倒的に高速ですね。(^_^)

その秘密は NetBeans のプロファイラで確認しました。

内部で Fork/Join Framework が使われてるのが確認されました。

1

Java は並行処理を簡単に実行できるようにいろいろがんばって作られてるようです。

ちなみに、アレイのサイズを21億個まで増大させたときのプログラムの実行結果は次のようになりました。

1回目 : Arrays.parallelSortの処理時間は、0時間0分26秒7820320810000005

2回目 : Arrays.parallelSortの処理時間は、0時間0分14秒215850219

3回目 : Arrays.parallelSortの処理時間は、0時間0分15秒21248125400000006

4回目 : Arrays.parallelSortの処理時間は、0時間0分14秒17695699800000142

5回目 : Arrays.parallelSortの処理時間は、0時間0分15秒21644380900000115

6回目 : Arrays.parallelSortの処理時間は、0時間0分14秒13889982600000117

7回目 : Arrays.parallelSortの処理時間は、0時間0分15秒3859477300000016

8回目 : Arrays.parallelSortの処理時間は、0時間0分14秒15733845600000151

9回目 : Arrays.parallelSortの処理時間は、0時間0分15秒042537343000001115

10回目 : Arrays.parallelSortの処理時間は、0時間0分14秒10847939100000126

11回目 : Arrays.parallelSortの処理時間は、0時間0分15秒31738622100000136

12回目 : Arrays.parallelSortの処理時間は、0時間0分14秒09331228100000111

13回目 : Arrays.parallelSortの処理時間は、0時間0分15秒23933288000000097

14回目 : Arrays.parallelSortの処理時間は、0時間0分14秒09788163900000058

15回目 : Arrays.parallelSortの処理時間は、0時間0分15秒2869010420000002

16回目 : Arrays.parallelSortの処理時間は、0時間0分14秒1130110920000007

17回目 : Arrays.parallelSortの処理時間は、0時間0分15秒037243257000000085

18回目 : Arrays.parallelSortの処理時間は、0時間0分14秒1627590560000005

19回目 : Arrays.parallelSortの処理時間は、0時間0分15秒16421842200000114

20回目 : Arrays.parallelSortの処理時間は、0時間0分14秒3338693370000012

<—– Arrays.parallelSortの平均処理時間は、0時間0分14秒6845915220000016 —–>

1回目 : Arrays.sortの処理時間は、0時間3分46秒10638811700002293

2回目 : Arrays.sortの処理時間は、0時間3分45秒5415704870000013

3回目 : Arrays.sortの処理時間は、0時間3分44秒14708787200001439

4回目 : Arrays.sortの処理時間は、0時間3分44秒28659846600001515

5回目 : Arrays.sortの処理時間は、0時間3分44秒2646577520000051

6回目 : Arrays.sortの処理時間は、0時間3分43秒6922063590000107

7回目 : Arrays.sortの処理時間は、0時間3分43秒25756076300001496

8回目 : Arrays.sortの処理時間は、0時間3分44秒48740214200000764

9回目 : Arrays.sortの処理時間は、0時間3分42秒6569463620000136

10回目 : Arrays.sortの処理時間は、0時間3分42秒32911070500000505

11回目 : Arrays.sortの処理時間は、0時間3分41秒22716906600001607

12回目 : Arrays.sortの処理時間は、0時間3分41秒819911870000027

13回目 : Arrays.sortの処理時間は、0時間3分41秒3822147500000028

14回目 : Arrays.sortの処理時間は、0時間3分41秒0946705690000158

15回目 : Arrays.sortの処理時間は、0時間3分42秒02558318500001633

16回目 : Arrays.sortの処理時間は、0時間3分51秒4318844270000284

17回目 : Arrays.sortの処理時間は、0時間3分52秒048210971000003155

18回目 : Arrays.sortの処理時間は、0時間3分52秒01929548700002215

19回目 : Arrays.sortの処理時間は、0時間3分52秒04963036800000964

20回目 : Arrays.sortの処理時間は、0時間3分52秒09709150600002658

<—– Arrays.sortの平均処理時間は、0時間3分46秒7195662190000007 —–>

Java8 の正式リリースが待ち遠しいです!

ちなみに 9 月 9 日にリリース予定だったのですが、どうやら遅れそうです。

ツイッター上では 2014 年になるとか・・・つぶやかれていました。

今のうちにもっと情報集めて Java8 をしっかり楽しめるようにがんばってみるとしよう。(*^o^*)

Hatena タグ: