もっと Lambda その14

今日も朝早くから「もっと Lambda」シリーズの始まりです。

Java Day Tokyo 2013 でテストパイロットを大募集していたらしいので UnaryOperator を試しがてらにちょっと確認を。

まず UnaryOperator の確認をします。

java.​util.​function

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T,T>

An operation upon a single operand yielding a result. The operand and the result are of the same type. This is a specialization of Function for the case where the operand and result are of the same type.

パラメータ:

T – the type of operand to apply and of the result

日付:

1.8

参照:

Function

 

そして今回使う DoubleUnaryOperator は次のように double 専用に用意されたものです。

java.​util.​function

@FunctionalInterface
public interface DoubleUnaryOperator

An operation on a double operand yielding a double result. This is the primitive type specialization of UnaryOperator for double.

日付:

1.8

参照:

UnaryOperator

applyAsDouble(double operand) は次のようになってます。

java.​util.​function.​DoubleUnaryOperator

public double applyAsDouble(double operand)

Returns the double result of the operation upon the double operand.

パラメータ:

operand – the operand value

戻り値:

the operation result value

 

それでは無限小から 1 を引いた値の表示とその値と無限小が等しいか確認するプログラムを創ってみました。

ついでに無限小から無限小を引いてみました。(普通ありえない計算ですよね(^_^;)

package jp.yucchi.tryintunaryoperator;

import java.util.function.DoubleUnaryOperator;

public class TryIntUnaryOperator {

    public static void main(String[] args) {
        
        DoubleUnaryOperator operator = f -> f - 1;
        double j = operator.applyAsDouble(Double.NEGATIVE_INFINITY);
        System.out.println(j);
        if(Double.NEGATIVE_INFINITY == j){
            System.out.println("無限小");
        }else{
            System.out.println("なんでやねん。");
        }
        
        
        DoubleUnaryOperator operator2 = f -> f - Double.NEGATIVE_INFINITY;
        double k = operator2.applyAsDouble(Double.NEGATIVE_INFINITY);
        System.out.println(k);
        if(0 == k){
            System.out.println("0");
        }else{
            System.out.println("むりぽ");
        }
    }
}

実行結果は次のように期待通りになりました。

 

-Infinity
無限小
NaN
むりぽ

 

ここでバグがでたら片言の英語で「なんでやねん?」と言ってやろうと思ったがこんな単純なバグはそうそうあるもんじゃないですね。

Hatena タグ:

 

もっと Lambda その13

今日のエントリーも「もっと Lambda」シリーズです。

今回はよく使われるデザインパターンで知られている Factory Method pattern を Java8 を使ってコーディングしてみます。

ちなみにこのネタは海外のサイトで紹介されていたものです。

それを少し変えて写経しただけですが随分シンプルになるので感激です。

それでは現在の Java だと下記のようになります。

package jp.yucchi.factorymethodpattern4oldjava;

public interface Airplane {

    public void pilot();

    public void maintain();
}

package jp.yucchi.factorymethodpattern4oldjava;

public class JetAirplane implements Airplane {

    @Override
    public void pilot() {
        System.out.println("ジェット機を操縦します。");
    }

    @Override
    public void maintain() {
        System.out.println("ジェット機を整備します。");
    }
}

package jp.yucchi.factorymethodpattern4oldjava;

public class FighterPlane implements Airplane {

    @Override
    public void pilot() {
        System.out.println("戦闘機を操縦します。");
    }

    @Override
    public void maintain() {
        System.out.println("戦闘機を整備します。");
    }
}

package jp.yucchi.factorymethodpattern4oldjava;

abstract class AirplanePilot {

    public abstract Airplane getAirplane();

    public void pilotAirplane() {
        getAirplane().pilot();
    }

    public void maintainAirplane() {
        getAirplane().maintain();
    }
}

class JetAirplanePilot extends AirplanePilot {

    @Override
    public Airplane getAirplane() {
        return new JetAirplane();
    }
}

class FighterPlanePilot extends AirplanePilot {

    @Override
    public Airplane getAirplane() {
        return new FighterPlane();
    }
}

package jp.yucchi.factorymethodpattern4oldjava;

public class FactoryMethodPattern4OldJava {

    public static void main(String[] args) {
        pilotAirplane(new JetAirplanePilot());
        pilotAirplane(new FighterPlanePilot());
    }

    private static void pilotAirplane(AirplanePilot aPilot) {
        System.out.println("I pilot a new airplane.");
        aPilot.pilotAirplane();
        aPilot.maintainAirplane();
    }
}

Factory Method pattern でよく見かける典型的なサンプルですね。

インスタンスの生成をサブクラスに任せることによって柔軟に生成するインスタンスを選択することを可能としています。

では Java8 ではどのようなコードになるのでしょうか?

package jp.yucchi.factorymethodpattern4lambda;

public interface Airplane {

    public void pilot();

    public void maintain();
}

package jp.yucchi.factorymethodpattern4lambda;

public class JetAirplane implements Airplane {

    @Override
    public void pilot() {
        System.out.println("ジェット機を操縦します。");
    }

    @Override
    public void maintain() {
        System.out.println("ジェット機を整備します。");
    }
}

package jp.yucchi.factorymethodpattern4lambda;

public class FighterPlane implements Airplane {

    @Override
    public void pilot() {
        System.out.println("戦闘機を操縦します。");
    }

    @Override
    public void maintain() {
        System.out.println("戦闘機を整備します。");
    }
}

package jp.yucchi.factorymethodpattern4lambda;

public interface AirplanePilot {

    public Airplane getAirplane();

    public default void pilotAirplane() {
        getAirplane().pilot();
    }

    public default void maintainAirplane() {
        getAirplane().maintain();
    }
}

package jp.yucchi.factorymethodpattern4lambda;

public class FactoryMethodPattern4Lambda {

    public static void main(String[] args) {
        pilotAirplane(JetAirplane::new);
        pilotAirplane(FighterPlane::new);
    }

    static void pilotAirplane(AirplanePilot aPilot) {
        System.out.println("I pilot a new airplane.");
        aPilot.pilotAirplane();
        aPilot.maintainAirplane();
    }
}

Java8 では抽象化クラス AirplanePilot とそれの具象化クラス二つが必要とされません。

その代わりに、Java8 の新機能の Default methods ( Virtual extension methods ) を実装したインターフェイスを利用します。

実行結果はどちらも次のようになります。

I pilot a new airplane.
ジェット機を操縦します。
ジェット機を整備します。
I pilot a new airplane.
戦闘機を操縦します。
戦闘機を整備します

実にシンプルで綺麗なコードで Factory Method pattern が実装できてしまうんですね!

Hatena タグ: