normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

今更 Java8 を使ってみる ~その1 Lambda 編~

あまりにも Java8 を追っていなかったので、こんな大晦日の晩にちょっくら Lambda をいじってみた。

開発環境

NetBeansIntelliJ さんでは気軽にいじれるようだが、Eclipse さんではつい最近までいろいろしないと動かなかったらしい。昨今は以下の記事を見ればわかる通り、Eclipse IDE with JDK 8 support が(正式ではないが)リリースされているため、こちらを利用することで Lambda を利用できる。

上記の記事を参考に、Eclipse IDE with JDK 8 support と JDK8 をインストールすることで Eclipse を利用した開発環境の構築が可能だ。

簡単な構文で確認

以下のコードを実行して実行結果を確認してみた。今まで長々と匿名インターフェースを実装していたものがだいぶシンプルになっている。

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

public class Hello {

	interface HelloService {
		String say(String first, String second);
	}

	public static void main(String[] args) {

		final MyCounter counter = new MyCounter();

		// Enumerable.Range() が無いのでそれっぽいのにはしてみた
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
		for (int n : list) {
			HelloService service = (first, second) -> first + "#" + second
					+ " No." + counter.count();
			System.out.println("service = " + service.say("aaa", "bbb"));
		}

		System.out.println(//
				Arrays.stream(new int[] { 1, 2, 3, 4, 5 }).average()
						.getAsDouble());
	}
}

class MyCounter {
	int value = 0;

	public int count() {
		return ++value;
	}
}
  • 実行結果
service = aaa#bbb No.1
service = aaa#bbb No.2
service = aaa#bbb No.3
service = aaa#bbb No.4
service = aaa#bbb No.5

「String HelloService#say(String, String)」シグネチャのインターフェースに対し、main()メソッド内でラムダ式を利用してメソッド本体を定義して利用している。
実行結果は MyCounter インスタンスの値を利用している。この際、MyCounter インスタンスは final 定義であることに注意していただきたい(なので、final int counter =0; とかすると counter++ でコンパイルエラーになる)。

Stream API を試す

今度は Stream API を試してみる。こちらは map-filter-reduce という関数型チックなコレクション処理を容易に実現できるようになっている。以下にサンプルを記載する。

package org.mydomain.stream;

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

public class HelloStream {
	public static void main(String[] args) {

		List<Person> persons = new ArrayList<>();
		Person person;

		person = new Person();
		person.setName("幼女");
		person.setAge(11);
		persons.add(person);

		person = new Person();
		person.setName("女子");
		person.setAge(21);
		persons.add(person);

		person = new Person();
		person.setName("なかなか幼女");
		person.setAge(9);
		persons.add(person);

		person = new Person();
		person.setName("すごく幼女");
		person.setAge(6);
		persons.add(person);

		// 私はロリコンではありません ①
		persons.stream()
				.filter(p -> p.getAge() <= 12)
				.forEach(
						p -> System.out.println("この幼女は " + p.getAge()
								+ "歳。(*´Д`)ハァハァ"));

		// 私はロリコンではありません ②
		// なぜか p.setName(""); return p; で変数解決できなかったので変更
		persons.stream().map(p -> p.setName("これは幼女 (*´Д`)ハァハァ"))
				.forEach(System.out::println);

		System.out.println(//
				Arrays.stream(new int[] { 1, 2, 3, 4, 5 }).average()
						.getAsDouble());

		// なぜか toString() が必要な辺りに Eclipse のインテリセンスがいまいちなことを感じる…
		Arrays.asList("卑猥", "淫猥", "淫乱", "淫靡", "普通").stream()
				.map(s -> "割と" + s.toString() + "!!")
				.forEach(System.out::println);
	}
}

class Person {
	String name;
	int age;

	public String getName() {
		return name;
	}

	public Person setName(String name) {
		this.name = name;
		return this;
	}

	public int getAge() {
		return age;
	}

	public Person setAge(int age) {
		this.age = age;
		return this;
	}

	@Override
	public String toString() {
		return name + " は " + age + "歳";
	}
}

上記の実行結果は以下になる。

この幼女は 11歳。(*´Д`)ハァハァ
この幼女は 9歳。(*´Д`)ハァハァ
この幼女は 6歳。(*´Д`)ハァハァ
これは幼女 (*´Д`)ハァハァ は 11歳
これは幼女 (*´Д`)ハァハァ は 21歳
これは幼女 (*´Д`)ハァハァ は 9歳
これは幼女 (*´Д`)ハァハァ は 6歳
3.0
割と卑猥!!
割と淫猥!!
割と淫乱!!
割と淫靡!!
割と普通!!

ご覧のとおり、コレクション処理が容易になっている。が、上記をご覧になっていただければわかると思うが、一部 Eclipse のインテリセンスがうまく動作していないと思われる個所もある。