火曜日, 12月 31, 2013

Java8 - stream

Java8の変更点の目玉の一つがstreamである.今までのfor文よりもずっときれいにデータプロセス用のコードが書けるようになる.

以下の例は,とある場外取引システムにおけるトレードデータから以下の条件を満たすものを抽出した例.

  • TradeDateが2013年1月1日以降
  • アクション名がADD
  • 取引相手先国が日本

package org.tanuneko.sample;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;

public class StreamSample {

    private static List<Trade> trades = populateTrades();
    private static List<CounterParty> cps = populateCPs();

    private static List<Trade> populateTrades() {
        List<Trade> list = new ArrayList<Trade>();
        list.add( new Trade( "TRD111.1", 1, "ADD", parse( "2013-01-20" ), 1001, true, "15000000ABC" ) );
        list.add( new Trade( "TRD123.1", 1, "ADD", parse( "2013-01-20" ), 1006, true, "16000000ABC" ) );
        list.add( new Trade( "TRD123.1", 2, "MOD", parse( "2013-01-26" ), 1006, true, "16000000ABC" ) );
        list.add( new Trade( "TRD145.1", 1, "ADD", parse( "2013-09-20" ), 1009, true, "T7000000ABC" ) );
        list.add( new Trade( "TRD133.1", 1, "ADD", parse( "2013-06-20" ), 1001, true, "16600000ABC" ) );
        list.add( new Trade( "TRD080.1", 1, "ADD", parse( "2010-07-20" ), 1001, true, "TRD080.1" ) );
        list.add( new Trade( "TRD092.1", 1, "ADD", parse( "2010-09-15" ), 1008, true, "TRD092.1" ) );
        list.add( new Trade( "TRD092.1", 2, "MOD", parse( "2010-09-30" ), 1020, true, "TRD092.1" ) );
        return list;
    }

    private static List<CounterParty> populateCPs() {
        List<CounterParty> cps = new ArrayList<CounterParty>();
        cps.add( new CounterParty( 1001, "US" ) );
        cps.add( new CounterParty( 1009, "Ireland" ) );
        cps.add( new CounterParty( 1006, "Japan" ) );
        cps.add( new CounterParty( 1020, "India" ) );
        cps.add( new CounterParty( 1008, "France" ) );
        cps.sort((l,r) -> l.getCounterPartyId() - r.getCounterPartyId()  );
        return cps;
    }

    private static ZonedDateTime parse( String date ) {
        return ZonedDateTime.parse( date + "T00:00:00-05:00[America/New_York]" );
    }

    public static void main( String args[] ) {
        
        trades.stream()
                .filter(t -> t.getTradeDate().isAfter(parse("2013-01-01")))
                .filter(t -> t.getActionName().equals("ADD") )
                .filter(t -> cps.stream().anyMatch( x -> x.getCounterPartyId() == t.getCounterPartyId() && x.getCountry().equals( "Japan" ) ) )
                .forEach(t -> System.out.println(t));
        cps.forEach( c -> System.out.println( c ) );
    }
}

class CounterParty {

    private int counterPartyId;
    private String country;

    CounterParty(int counterPartyId, String country) {
        this.counterPartyId = counterPartyId;
        this.country = country;
    }

    public int getCounterPartyId() {
        return counterPartyId;
    }

    public String getCountry() {
        return country;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CounterParty that = (CounterParty) o;

        if (counterPartyId != that.counterPartyId) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return counterPartyId;
    }

    @Override
    public String toString() {
        return "CounterParty{" +
                "counterPartyId=" + counterPartyId +
                ", country='" + country + '\'' +
                '}';
    }
}

class Trade {

    private String tradeId;
    private int eventId;
    private String actionName;
    private ZonedDateTime tradeDate;
    private int counterPartyId;
    private boolean isSDREligible;
    private String USI;

    public Trade( String tradeId, int eventId, String actionName, ZonedDateTime tradeDate,
                   int counterPartyId, boolean isSDREligible, String USI ) {
        this.tradeId = tradeId;
        this.eventId = eventId;
        this.actionName = actionName;
        this.tradeDate = tradeDate;
        this.counterPartyId = counterPartyId;
        this.isSDREligible = isSDREligible;
        this.USI = USI;
    }

    public String getTradeId() {
        return tradeId;
    }

    public int getEventId() {
        return eventId;
    }

    public String getActionName() {
        return actionName;
    }

    public ZonedDateTime getTradeDate() {
        return tradeDate;
    }

    public int getCounterPartyId() {
        return counterPartyId;
    }

    public boolean isSDREligible() {
        return isSDREligible;
    }

    public String getUSI() {
        return USI;
    }

    @Override
    public String toString() {
        return "Trade{" +
                "tradeId='" + tradeId + '\'' +
                ", eventId=" + eventId +
                ", actionName='" + actionName + '\'' +
                ", tradeDate=" + tradeDate +
                ", counterPartyId=" + counterPartyId +
                ", isSDREligible=" + isSDREligible +
                ", USI='" + USI + '\'' +
                '}';
    }
}



月曜日, 12月 30, 2013

Java8 新しい Date and Time API

Java8の新機能の一つが新しいDate and Time API(JSR-310)の追加だろう.ご存じの通り標準SDKに付属していた従来のDate関連のクラスは機能が貧弱であったり,Calendarクラスmutabilityに起因する懸念から,Joda Timeを使っていた.
この新しいDate and Time API(JSR-310)を使うか,Joda Timeを使い続けるかはあなた次第だが,少なくとも旧来のDateの実装で無理をし続ける必要だけはなさそうである.

ちなみに以下のサイトは良質なDate and Time APIのサマリ,Joda TimeとJSR-310の比較記事だと思う.

http://sssslide.com/www.slideshare.net/JustinSDK/2013-java-developer-day-joda-timejsr310
http://howtodoinjava.com/2013/05/15/date-and-time-api-changes-in-java-8-lambda/

LocalDate, ZoneDateTimeそしてDateTimeFormatterの使用例

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;

/**
 * Created by morinoko on 12/29/13.
 */
public class Kerorin {

    public static void main( String args[] ) {

        LocalDate date = LocalDate.now();
        System.out.println( "today:" + date );
        System.out.println( "after five days from today:" + date.plusDays(5) );
        //ZoneId.getAvailableZoneIds().forEach(x -> System.out.println(x));
        ZonedDateTime zTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
        DateTimeFormatter fmt = new DateTimeFormatterBuilder().append( DateTimeFormatter.ISO_DATE )
                .appendLiteral("-")
                .appendZoneId().toFormatter();

        System.out.println( fmt.format( zTime ) );
        System.out.println( "Converting to JST" );
        System.out.println( fmt.format( zTime.withZoneSameLocal( ZoneId.of( "Asia/Tokyo" ) ) ) );
      }

}



Java8 ラムダ

関数言語の使用者には十二分におなじみのlambda式がついにJava バージョン8で正式採用である.今まで無名クラスを書いてはコードが汚れるたびに,関数ポインタのように書ければなぁ,と思っていたのだが..これからはLambda式で綺麗にかけるようになるわけである.実にありがたい.

Lambda式を使ってリストをソート後ダンプ

import java.util.Arrays;
import java.util.List;

/**
 * Created by morinoko on 12/29/13.
 */
public class Tanukin {

    public static void main( String args[] ) {

        List<String> list = Arrays.asList( new String[]{"tanu", "tanuku", "hello"} );
        list.sort( (l,r) -> l.length() - r.length()  );
        list.forEach( s -> System.out.println( s ) );

    }

}
C++での例
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

bool cmp(const string& l, const string& r) { return l.size() < r.size(); }
void dump(const string& s){ cout << s << endl; }

int main() {

 vector<string> v;
 v.push_back( "tanu" ); v.push_back( "tanuku" ); v.push_back( "hello" );
 sort( v.begin(), v.end(), cmp );
 for_each( v.begin(), v.end(), dump );
 
}