Java6では正式にクロージャはサポートされていませんが、内部クラスを利用して少し工夫すれば実現することができます。クロージャを実現するには、次のポイントを考慮する必要があります。

  • 内部クラスから外部の変数の値を参照・変更できる必要がある
  • 内部クラスから外部の変数の値を参照するには、その変数はfinalで宣言する必要がある
  • 変数をfinalで宣言してしまうと値の変更ができないため、オブジェクトで変数をラップする必要がある

クロージャのサンプルとして、Go言語のフィボナッチ数列のサンプルコードをJava言語で表現してみました。

Go(関数のみ抜粋)

// fib returns a function that returns
// successive Fibonacci numbers.
func fib() func() int {
	a, b := 0, 1
	// ↓これがクロージャ
	return func() int {
		a, b = b, a+b
		return b
	}
}

Java

public class Fibonacci {
	public static void main(String[] args) {
		Fibonacci fib = new Fibonacci();
		Func<Integer> f = fib.newFibonacci();
		println(f.call(), f.call(), f.call(), f.call(), f.call(), f.call(), f.call(), f.call(), f.call());
	}
	
	private static void println(Integer ...integers) {
		for(Integer i : integers) {
			System.out.print(i);
			System.out.print(" ");
		}
	}

	private class IntHolder {
		public int value;
		public IntHolder(int value) {
			this.value = value;
		}
	}
	
	public interface Func<R> {
		R call();
	}
	
	public Func<Integer> newFibonacci() {
		// インナークラスからの変数の参照はfinalのみ許可される。
		// インナークラスから値の更新を行えるようにオブジェクトでラップする。
		final IntHolder a = new IntHolder(0);
		final IntHolder b = new IntHolder(1);
		// ↓これがクロージャ
		return new Func<Integer>() {
			@Override
			public Integer call() {
				int fib = a.value + b.value;
				a.value = b.value;
				b.value = fib;
				return fib;
			}
		};
	}
}

クロージャをサポートしている他の言語と比べると少し面倒ですね・・・

参考

クロージャ - Wikipedia
いまさらだけど、Java言語にはクロージャーがない
Re: いまさらだけど、Java言語にはクロージャーがない


Go言語で何か簡単なものを作ってみようと思い、公式サイトを見ているとフィボナッチ数列のサンプルが目にとまりました。

// fib returns a function that returns
// successive Fibonacci numbers.
func fib() func() int {
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return b
	}
}

このサンプル、よく見るとクロージャなんですね。使い方は次のとおり。一旦、変数fに代入して呼び出している点がポイントです。

func main() {
	f := fib()
	println(f(),f(),f(),f())
}

何か作ってみたかったので再帰版の関数も追加してみました。

fibonacci.go

package main

// fib returns a function that returns
// successive Fibonacci numbers.
func fib() func() int {
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return b
	}
}

func fib_recursive(n int) int {
	if n > 2 {
		return fib_recursive(n - 1) + fib_recursive(n - 2)
	}
	return n
}

func main() {
	f := fib() 
	f2 := fib() 
	println(f(), f(), f(), f(), f())
	println(f2(), f2(), f2(), f2(), f2())
	println(fib_recursive (1), fib_recursive (2), fib_recursive (3), fib_recursive (4), fib_recursive (5))
}

今回はメイクファイルも作ってみました。なんか久々で新鮮です。そういえば最近はmavenやらantばかりで、メイクファイルなんて10年以上書いてないなー

Makefile

#
# ARM Architecture
#
G_ARM=5g
L_ARM=5l
#
# x86, x86_32 Architecture
#
G_X86=8g
L_X86=8l
#
# AMD64, x86_64 Architecture
#
G_AMD=6g
L_AMD=6l
#
# Compiler And Linker Options
#
GFLAGS=
LFLAGS=
#
# TARGET
#
SRC=fibonacci.go
OBJ=$(SRC:%.go=%.6)
TARGET=fibonacci
#
# rules
#
%.5: %.go
	$(G_ARM) $(GFLAGS) $<

%: %.5
	$(L_ARM) $(LFLAGS) -o $@ $^

%.6: %.go
	$(G_AMD) $(GFLAGS) $<

%: %.6
	$(L_AMD) $(LFLAGS) -o $@ $^

%.8: %.go
	$(G_X86) $(GFLAGS) $<

%: %.8
	$(L_X86) $(LFLAGS) -o $@ $^

#
# 
#
all: $(TARGET)

$(TARGET): $(OBJ)

clean:
	rm $(OBJ) $(TARGET)