前回のはint型の配列にしか対応してなかったので、全型に対応できるようにしてみた。
前回の: http://d.hatena.ne.jp/taka_2/20071220#p1
さすがにjava.lang.reflect.Methodはないだろうと思い、interfaceを定義してそれを実装することでmapメソッド中の処理を実装するようにした。
下記の例では、PlusOneProcessMapクラスが、処理内容を定義している。(Rubyのmap/collectメソッドでいうところのブロックの内部に相当)
便宜上NumericProcessMapというAdapterクラスを定義し、数値を扱うプリミティブ型をまとめて扱えるようにした。この結果、PlusOneProcessMapクラスでは、doubleを扱う処理のみ記述することでintやfloatにも対応できたことになる。
import java.lang.reflect.Array; /* * javaでmapメソッドを実現するテスト */ public class maptest { /* * mapメソッドで処理する方法を定めるインタフェース */ interface ProcessMap { public boolean processMap(boolean data); public byte processMap(byte data); public char processMap(char data); public double processMap(double data); public float processMap(float data); public int processMap(int data); public long processMap(long data); public short processMap(short data); public Object processMap(Object data); } /* * 配列と処理を渡すと、配列の各要素に対してそれぞれ処理を行った結果の配列を返す。 * 配列を渡さない場合は、そのオブジェクトをそのまま返却する。 */ public Object map(Object arrObj, ProcessMap pm) { // 渡されたオブジェクトが配列でない場合は、そのまま返却する。 if(!arrObj.getClass().isArray()) { return arrObj; } // 渡された配列の型 Class componentType = arrObj.getClass().getComponentType(); // 渡された配列のサイズ int size = Array.getLength(arrObj); // 渡された配列と同じ型、同じサイズの配列オブジェクトを生成する。 Object result = Array.newInstance(componentType, size); // 配列の各要素について、processMapメソッドを実行し、結果をresultへ格納する。 for(int i=0; i<size; i++) { if(componentType.equals(Boolean.TYPE)) { Array.setBoolean(result, i, pm.processMap(Array.getBoolean(arrObj, i))); } else if(componentType.equals(Byte.TYPE)) { Array.setByte(result, i, pm.processMap(Array.getByte(arrObj, i))); } else if(componentType.equals(Character.TYPE)) { Array.setChar(result, i, pm.processMap(Array.getChar(arrObj, i))); } else if(componentType.equals(Double.TYPE)) { Array.setDouble(result, i, pm.processMap(Array.getDouble(arrObj, i))); } else if(componentType.equals(Float.TYPE)) { Array.setFloat(result, i, pm.processMap(Array.getFloat(arrObj, i))); } else if(componentType.equals(Integer.TYPE)) { Array.setInt(result, i, pm.processMap(Array.getInt(arrObj, i))); } else if(componentType.equals(Long.TYPE)) { Array.setLong(result, i, pm.processMap(Array.getLong(arrObj, i))); } else if(componentType.equals(Short.TYPE)) { Array.setShort(result, i, pm.processMap(Array.getShort(arrObj, i))); } else { // primitive型ではない。 Array.set(result, i, pm.processMap(Array.get(arrObj, i))); } } return result; } /* * 数値型に対するmap処理 * boolean, char, Objectはそのまま返します。 */ class NumericProcessMap implements ProcessMap { public boolean processMap(boolean data) { return data; } public byte processMap(byte data) { return (byte)processMap((double)data); } public char processMap(char data) { return data; } public double processMap(double data) { return data; } public float processMap(float data) { return (float)processMap((double)data); } public int processMap(int data) { return (int)processMap((double)data); } public long processMap(long data) { return (long)processMap((double)data); } public short processMap(short data) { return (short)processMap((double)data); } public Object processMap(Object data) { return data; } } class PlusOneProcessMap extends NumericProcessMap { public double processMap(double data) { return data + 1; } } /* * テストドライバ */ public static void main(String[] args) { new maptest(); } public maptest() { int[] iArray = {1, 2, 3}; float[] fArray = {2.2f, 3.3f, 4.4f}; PlusOneProcessMap popm = new PlusOneProcessMap(); int[] iArrayMapped = (int[])map(iArray, popm); float[] fArrayMapped = (float[])map(fArray, popm); System.out.println("-- iArray map前 --"); printArray(iArray); System.out.println("-- iArray map後 --"); printArray(iArrayMapped); System.out.println("-- fArray map前 --"); printArray(fArray); System.out.println("-- fArray map後 --"); printArray(fArrayMapped); } private void printArray(Object arr) { for(int i=0; i<Array.getLength(arr); i++) { System.out.println(i + ":" + Array.get(arr, i)); } } }
これの結果は以下のように表示される。
>java maptest -- iArray map前 -- 0:1 1:2 2:3 -- iArray map後 -- 0:2 1:3 2:4 -- fArray map前 -- 0:2.2 1:3.3 2:4.4 -- fArray map後 -- 0:3.2 1:4.3 2:5.4 >