火曜日, 1月 21, 2014

Java8 - 関数の合成 1 .. andThen

Java8のラムダは関数の合成に対する操作も用意されている.
そのうちの一つがandThen()である.以下の例は引換券のIDを入力として本のタイトルを返す.


package org.tanuneko;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

public class AndThenSample {

    private static List<ClaimTicket> tickets;

    private static void init() {

        tickets = new ArrayList<ClaimTicket>();
        tickets.add( new ClaimTicket( 1, new Book( Janre.Sports, "All about Payton Manning") ) );
        tickets.add( new ClaimTicket( 2, new Book( Janre.Sports, "Andy - how to win at playoff") ) );
        tickets.add( new ClaimTicket( 3, new Book( Janre.Education, "ABC") ) );
        tickets.add( new ClaimTicket( 101, new Book( Janre.Education, "Waldorf education - how it works") ) );

    }

    public static void main( String args[] ) {

        init();
        Function<ClaimTicket,Book> getBookByClaimId = ClaimTicket::getBook;
        Function<Book,String> getTitle = Book::getTitle;
        Function<ClaimTicket,String> getTitleOfClaimedBook = getBookByClaimId.andThen(getTitle);
        System.out.println( tickets.stream().filter(x->x.getId()<100)
                .map(getTitleOfClaimedBook)
                .collect( Collectors.reducing((x,y)-> x + "," + y))
                .toString() );
    }

}

enum Janre {
    Education,
    Sports
}

class Book {

    private Janre janre;
    private String title;

    public Book( Janre janre, String title ) {
        this.janre = janre;
        this.title = title;
    }

    public Janre getJanre() { return janre; }
    public String getTitle() { return title; }
}

class ClaimTicket {

    private int id;
    private Book book;

    public ClaimTicket( final int id, final Book book ) {
        this.id = id;
        this.book = book;
    }

    public int getId() { return id; }
    public Book getBook() { return book; }
}

Java8 - Infiniteのstream

Stream.iterate()を使うとinfiniteのstreamを生成できる.infiniteのstream - ここではiterateの2番目の引数UnaryOperator<T> ( 引数Tを取り,処理後結果として入力と同型Tを返す.つまりFunction<T,T> )を無制限に適用しstreamの要素を生成する.

おおよその場合はStream.limit()と組み合わせて使う.
package org.tanuneko;

import java.util.stream.Stream;

public class ToMapSample {

    public static void main( String args[] ) {

        Stream.iterate( 'S', (x)->"ABC".charAt((int)(Math.random()*3)))
                .limit(30)
                .forEach(System.out::println);

    }

}

土曜日, 1月 18, 2014

Java8 - キーごとに分類

以下の例は本オブジェクトのリストに対し,各本のジャンルごとに分類した結果をマップにして返す例.IntelliJのエディタではシンタックスエラーが出るが,コンパイルも実行も問題ない.


package org.tanuneko;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import static java.util.stream.Collectors.*;

public class ToMapSample {

    private static List<Book> books;

    private static void init() {

        books = new ArrayList<Book>();
        books.add( new Book( Janre.Sports, "All about Payton Manning") );
        books.add( new Book( Janre.Sports, "Andy - how to win at playoff")  );
        books.add( new Book( Janre.Education, "ABC") );
        books.add( new Book( Janre.Education, "Waldorf education - how it works")  );

    }

    public static void main( String args[] ) {

        init();
        Map<Janre,List<String>> map = books.stream()
                .collect(groupingBy(Book::getJanre,TreeMap::new,mapping(Book::getTitle,toList())));
        System.out.println(map);

    }

}

enum Janre {
    Education,
    Sports
}

class Book {

    private Janre janre;
    private String title;

    public Book( Janre janre, String title ) {
        this.janre = janre;
        this.title = title;
    }

    public Janre getJanre() { return janre; }
    public String getTitle() { return title; }
}




水曜日, 1月 15, 2014

Java8 - streamとDirectoryWalkerで効率よくファイル探索

Java IO CommonsのDirectoryWalkerとstreamを組み合わせて,効率よくファイルシステム上のデータを探すコード.かなり荒削りのサンプルだが,とりあえず動く.

package org.tanuneko.tanukin;

import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

public class DirWalker extends DirectoryWalker<File> {

    private static FileFilter filter = getFilter();

    public DirWalker() {

        super( filter,-1 );

    }

    protected void handleFile( File file, int depth, Collection<File> results ) {

        results.add( file );

    }

    public Collection<File> start( File startDir ) throws IOException {
        Collection<File> results = new ConcurrentLinkedQueue<File>();
        super.walk( startDir, results );
        return results;
    }

    public static void main(String args[] ) throws IOException {

        DirWalker walker = new DirWalker();
        System.out.println(
                        walker.start(new File("C:\\cygwin\\srv")).parallelStream()
                        .map(x -> x.getAbsolutePath())
                        .collect(Collectors.toStringJoiner("\n"))
                        .toString());

    }

    // if you want to handle directory, define below
    /*
    protected boolean handleDirectory( File dir, int depth, Collection<File> results ) {

        if( ".svn".equals( dir.getName() ) ) {
            return false;
        }
        else {
            return true;
        }
    }
    */

    private static FileFilter getFilter() {

        //    you can define filter
        //    IOFileFilter suffixFilt =  FileFilterUtils.suffixFileFilter( ".txt" );
        //    FileFilterUtils.makeSVNAware( suffixFilt );
        //   FileFilter filter = FileFilterUtils.or( suffixFilt );
        //    return filter;
        return null;

    }

}

日曜日, 1月 12, 2014

Java8 - オブジェクトへのmapper適用

以下の例はJava8のmapを用いて,

  1. カスタムオブジェクトItemのマスタリスト中から興味のある品だけを取り出し
  2. 更に10000円以上のものだけを選び
  3. かつ価格を安いものから昇順に並べる

例である.


package org.tanuneko;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Reducer {

    public static void main( String args[] ) {

        // since this is lazy evaluation, WareHouse::findItembyId is not called for all entries in item list held by WareHouse
        List<Integer> interests = Arrays.asList( 1,2,3,4,5,6 );
        List<Item> items = interests.stream().map(WareHouse::findItembyId)
                            .filter((x)->x.getPrice()>10000)
                            .sorted( (x,y)->x.getPrice() - y.getPrice() )
                            .collect(Collectors.toList());
        items.stream().forEach(System.out::println);
 
     }

}

class WareHouse {

    static final List<Item> items = genItems();

    public static Item findItembyId( int id )  {
        // better to use orElse()
        return items.stream().filter(x->x.getId()==id).findFirst().get();

    }

    private static List<Item> genItems() {
        List<Item> items = new ArrayList<>();
        items.add( new Item( 1, 500, "Basket" ) );
        items.add( new Item( 2,1200, "Rack" ) );
        items.add( new Item( 3, 700, "Small Table" ) );
        items.add( new Item( 4, 50000, "Granite Table" ) );
        items.add( new Item( 5, 15000, "Closet" ) );
        items.add( new Item( 6, 400, "Grout" ) );
        items.add( new Item( 7, 28000, "Small Couch" ) );
        return items;
    }
}

Items.java

package org.tanuneko;

public class Item {

    private int id;
    private int price;
    private String name;

    public Item( int id, int price, String name ) {
        this.id = id;
        this.price = price;
        this.name = name;
    }

    public int getId() { return id; }
    public int getPrice() { return price; }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "Item{" +
                "id=" + id +
                ", price=" + price +
                ", name='" + name + '\'' +
                '}';
    }
}

Item{id=5, price=15000, name='Closet'}
Item{id=4, price=50000, name='Granite Table'}

土曜日, 1月 11, 2014

Java8 - reduceとmapで集計

ついでにmapでカスタムオブジェクト群のあるフィールド値の合計をmapとreduceで行う例.

package org.tanuneko;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BinaryOperator;

public class Reducer {

    public static void main( String args[] ) {

        System.out.println( genItems().stream().map( Item::getPrice ).reduce( Integer::sum ).get() );
        
     }

    private static List<Item> genItems() {
        List<Item> items = new ArrayList<>();
        items.add( new Item( 500, "Basket" ) );
        items.add( new Item( 1200, "Rack" ) );
        items.add( new Item( 700, "Small Table" ) );
        items.add( new Item( 50000, "Granite Table" ) );
        items.add( new Item( 15000, "Closet" ) );
        items.add( new Item( 400, "Grout" ) );
        return items;
    }

    private static Item getCheapestOne() {
        return new Item( Integer.MIN_VALUE, "VOID" );
    }
}

package org.tanuneko;

public class Item {
    private int price;
    private String name;

    public Item( int price, String name ) {
        this.price = price;
        this.name = name;
    }

    public int getPrice() { return price; }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "Item{" +
                "price=" + price +
                ", name='" + name + '\'' +
                '}';
    }
}


Java8 - reduceで検索

Java8のstreamのreduceを使ってカスタムオブジェクト(この例ではItem)の検索をする例.


Item.java
package org.tanuneko;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BinaryOperator;

public class Reducer {

    public static void main( String args[] ) {

        BinaryOperator<Item> costsMore = (m,n)->
                                          { return ( m.getPrice() > n.getPrice() ? m:n ); };

        System.out.println(genItems().stream().reduce(getCheapestOne(), costsMore));
     }

    private static List<Item> genItems() {
        List<Item> items = new ArrayList<>();
        items.add( new Item( 500, "Basket" ) );
        items.add( new Item( 1200, "Rack" ) );
        items.add( new Item( 700, "Small Table" ) );
        items.add( new Item( 50000, "Granite Table" ) );
        items.add( new Item( 15000, "Closet" ) );
        items.add( new Item( 400, "Grout" ) );
        return items;
    }

    private static Item getCheapestOne() {
        return new Item( Integer.MIN_VALUE, "VOID" );
    }
}

Item.java

package org.tanuneko;

public class Item {
    private int price;
    private String name;

    public Item( int price, String name ) {
        this.price = price;
        this.name = name;
    }

    public int getPrice() { return price; }
    public String getName() { return name; }

    @Override
    public String toString() {
        return "Item{" +
                "price=" + price +
                ", name='" + name + '\'' +
                '}';
    }
}
実行結果
Item{price=50000, name='Granite Table'}