Skip to content

Instantly share code, notes, and snippets.

@htsign
Last active December 3, 2017 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save htsign/161a30a268df7dfba00c62de55a65ccb to your computer and use it in GitHub Desktop.
Save htsign/161a30a268df7dfba00c62de55a65ccb to your computer and use it in GitHub Desktop.
It provides some functional programming feature to Java5
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* {@code Iterable}に対する関数型プログラミングの機能を提供するクラスです。 (JDK 1.5)
*/
public final class IterableUtils<T> {
private final Iterable<T> values;
/**
* {@code IterableUtils}クラスのインスタンスを生成します。<br/>
* 主にメソッドチェーンを行いたい場合や計算結果を一時的に保持したい場合に使用します。<br/>
* 一度きりの計算を行う場合はインスタンスメソッドの代わりに静的メソッドを使用してください。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
*/
public IterableUtils(final Iterable<T> items) {
values = items;
}
/**
* {@code Iterable}の各要素に静的メソッドを適用した新たな{@code Iterable}のインスタンスを返します。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param returnType {@code method}が返却する型
* @param method 適用する静的メソッド
* @return 静的メソッドが適用された要素を持つ新たな{@code Iterable}のインスタンス
*/
public static <T, R> Iterable<R> map(
final Iterable<T> items,
final Class<R> returnType,
final Method method
) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return map(items, returnType, null, method);
}
/**
* {@code Iterable}の各要素にインスタンスメソッドを適用した新たな{@code Iterable}のインスタンスを返します。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param returnType {@code method}が返却する型
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param method 適用するインスタンスメソッド
* @return インスタンスメソッドが適用された要素を持つ新たな{@code Iterable}のインスタンス
*/
public static <T, R> Iterable<R> map(
final Iterable<T> items,
final Class<R> returnType,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (returnType != method.getReturnType())
throw new RuntimeException("type mismatch between 'returnType' and 'method#getReturnType'");
final List<R> list = new ArrayList<R>();
for (final T item : items) {
final R result = invokeMethod(obj, method, item);
list.add(result);
}
return Collections.unmodifiableList(list);
}
/**
* 提供された静的メソッドを用いて{@code Iterable}の要素を絞り込みます。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param method 絞り込みに使う静的メソッド (* このメソッドの戻り値の型は{@code boolean}である必要があります *)
* @return 絞り込まれた新たな{@code Iterable}のインスタンス
*/
public static <T> Iterable<T> filter(final Iterable<T> items, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return filter(items, null, method);
}
/**
* 提供されたメソッドを用いて{@code Iterable}の要素を絞り込みます。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param method 絞り込みに使うインスタンスメソッド (* このメソッドの戻り値の型は{@code boolean}である必要があります *)
* @return 絞り込まれた新たな{@code Iterable}のインスタンス
*/
public static <T> Iterable<T> filter(
final Iterable<T> items,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
final Class<?> returnType = method.getReturnType();
if (returnType != boolean.class && returnType != Boolean.class)
throw new RuntimeException("'method' must returns boolean type");
final List<T> list = new ArrayList<T>();
for (final T item : items) {
if (((Boolean)invokeMethod(obj, method, item)).booleanValue()) {
list.add(item);
}
}
return Collections.unmodifiableList(list);
}
/**
* {@code Iterable}のすべての要素に対して静的メソッドを呼び出します。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param method 呼び出される静的メソッド
*/
public static <T> void forEach(final Iterable<T> items, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
forEach(items, null, method);
}
/**
* {@code Iterable}のすべての要素に対してインスタンスメソッドを呼び出します。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param method 呼び出されるインスタンスメソッド
*/
public static <T> void forEach(
final Iterable<T> items,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
for (final T item : items) {
invokeMethod(obj, method, item);
}
}
/**
* {@code Iterable}のすべての要素に静的メソッドを適用していき単一の値になるように折り畳みます。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param initialValue アキュムレータに与える最初の値
* @param method 二つの引数を取り{@code initialValue}と同じ型を返す静的メソッド
*/
public static <T, R> R reduce(
final Iterable<T> items,
final R initialValue,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return reduce(items, null, initialValue, method);
}
/**
* {@code Iterable}のすべての要素にインスタンスメソッドを適用していき単一の値になるように折り畳みます。
*
* @param items 計算の対象とする{@code Iterable}のインスタンス
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param initialValue アキュムレータに与える最初の値
* @param method 二つの引数を取り{@code initialValue}と同じ型を返すインスタンスメソッド
*/
public static <T, R> R reduce(
final Iterable<T> items,
final Object obj,
final R initialValue,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
R acc = initialValue;
for (final T item : items) {
@SuppressWarnings("unchecked")
final R next = (R)method.invoke(obj, acc, item);
acc = next;
}
return acc;
}
/**
* {@code Iterable}の各要素に静的メソッドを適用します。
*
* @param returnType {@code method}が返却する型
* @param method 適用する静的メソッド
* @return 静的メソッドが適用された要素を持つ新たな{@code IterableUtils}のインスタンス
*/
public <R> IterableUtils<R> map(final Class<R> returnType, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<R>(map(values, returnType, method));
}
/**
* {@code Iterable}の各要素にインスタンスメソッドを適用します。
*
* @param returnType {@code method}が返却する型
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param method 適用するインスタンスメソッド
* @return インスタンスメソッドが適用された要素を持つ新たな{@code IterableUtils}のインスタンス
*/
public <R> IterableUtils<R> map(
final Class<R> returnType,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<R>(map(values, returnType, obj, method));
}
/**
* 提供された静的メソッドを用いて{@code Iterable}の要素を絞り込みます。
*
* @param method 絞り込みに使う静的メソッド (* このメソッドの戻り値の型は{@code boolean}である必要があります *)
* @return 絞り込まれた新たな{@code IterableUtils}のインスタンス
*/
public IterableUtils<T> filter(final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<T>(filter(values, method));
}
/**
* 提供されたインスタンスメソッドを用いて{@code Iterable}の要素を絞り込みます。
*
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param method 絞り込みに使うインスタンスメソッド (* このメソッドの戻り値の型は{@code boolean}である必要があります *)
* @return 絞り込まれた新たな{@code IterableUtils}のインスタンス
*/
public IterableUtils<T> filter(final Object obj, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<T>(filter(values, obj, method));
}
/**
* {@code Iterable}のすべての要素に対して静的メソッドを呼び出します。
*
* @param method 呼び出される静的メソッド
*/
public void forEach(final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
forEach(values, method);
}
/**
* {@code Iterable}のすべての要素に対してインスタンスメソッドを呼び出します。
*
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param method 呼び出されるインスタンスメソッド
*/
public void forEach(final Object obj, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
forEach(values, obj, method);
}
/**
* {@code Iterable}のすべての要素に静的メソッドを適用していき単一の値になるように折り畳みます。
*
* @param initialValue アキュムレータに与える最初の値
* @param method 二つの引数を取り{@code initialValue}と同じ型を返す静的メソッド
*/
public <R> R reduce(final R initialValue, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return reduce(values, initialValue, method);
}
/**
* {@code Iterable}のすべての要素にインスタンスメソッドを適用していき単一の値になるように折り畳みます。
*
* @param obj 実際に{@code method}を呼び出すインスタンス
* @param initialValue アキュムレータに与える最初の値
* @param method 二つの引数を取り{@code initialValue}と同じ型を返すインスタンスメソッド
*/
public <R> R reduce(
final Object obj,
final R initialValue,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return reduce(values, obj, initialValue, method);
}
/**
* {@code values}を返します。
*/
public Iterable<T> getValues() {
return values;
}
@SuppressWarnings("unchecked")
private static <T, R> R invokeMethod(
final Object obj,
final Method method,
final T value
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return (R)method.invoke(obj, value);
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* functional programming features (JDK 1.5).
*/
public class IterableUtils<T> {
private final Iterable<T> values;
/**
* create IterableUtils instance.
*/
public IterableUtils(final Iterable<T> items) {
values = items;
}
/**
* apply the function to each element of Iterable.
*
* @param items target Iterable
* @param returnType returning type of {@code method}
* @param method method to apply
* @return new instance of Iterable - applied on each element
*/
public static <T, R> Iterable<R> map(
final Iterable<T> items,
final Class<R> returnType,
final Method method
) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return map(items, returnType, null, method);
}
/**
* apply the function to each element of Iterable with instance method.
*
* @param items target Iterable
* @param returnType returning type of {@code method}
* @param obj it has an provided {@code method}
* @param method method to apply
* @return new instance of Iterable - applied on each element
*/
public static <T, R> Iterable<R> map(
final Iterable<T> items,
final Class<R> returnType,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (returnType != method.getReturnType())
throw new RuntimeException("type mismatch between 'returnType' and 'method#getReturnType'");
final List<R> list = new ArrayList<R>();
for (final T item : items) {
final R result = invokeMethod(obj, method, item);
list.add(result);
}
return Collections.unmodifiableList(list);
}
/**
* filter elements of Iterable by provided function.
*
* @param items target Iterable
* @param method filtering method (* it must be returned {@code boolean} type *)
* @return new instance of filtered Iterable
*/
public static <T> Iterable<T> filter(final Iterable<T> items, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return filter(items, null, method);
}
/**
* filter elements of Iterable by provided function with instance method.
*
* @param items target Iterable
* @param obj it has an provided {@code method}
* @param method filtering method (* it must be returned {@code boolean} type *)
* @return new instance of filtered Iterable
*/
public static <T> Iterable<T> filter(
final Iterable<T> items,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
final Class<?> returnType = method.getReturnType();
if (returnType != boolean.class && returnType != Boolean.class)
throw new RuntimeException("'method' must returns boolean type");
final List<T> list = new ArrayList<T>();
for (final T item : items) {
if (((Boolean)invokeMethod(obj, method, item)).booleanValue()) {
list.add(item);
}
}
return Collections.unmodifiableList(list);
}
/**
* call the provided function to each element of Iterable.
*
* @param items target Iterable
* @param method calling function
*/
public static <T> void forEach(final Iterable<T> items, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
forEach(items, null, method);
}
/**
* call the provided function to each element of Iterable with instance method.
*
* @param items target Iterable
* @param obj it has an provided {@code method}
* @param method calling function
*/
public static <T> void forEach(
final Iterable<T> items,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
for (final T item : items) {
invokeMethod(obj, method, item);
}
}
/**
* apply the function to each element of Iterable to reduce it to a single value.
*
* @param items target Iterable
* @param initialValue first value of accumulator
* @param method it has two arguments and returned a value has type same as type of {@code initialValue}
*/
public static <T, R> R reduce(
final Iterable<T> items,
final R initialValue,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return reduce(items, null, initialValue, method);
}
/**
* apply the function to each element of Iterable to reduce it to a single value.
*
* @param items target Iterable
* @param obj it has an provided {@code method}
* @param initialValue first value of accumulator
* @param method it has two arguments and returned a value has type same as type of {@code initialValue}
*/
public static <T, R> R reduce(
final Iterable<T> items,
final Object obj,
final R initialValue,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
R acc = initialValue;
for (final T item : items) {
@SuppressWarnings("unchecked")
final R next = (R)method.invoke(obj, acc, item);
acc = next;
}
return acc;
}
/**
* apply the function to each element of Iterable.
*
* @param returnType returning type of {@code method}
* @param method method to apply
* @return new instance of IterableUtils - applied on each element
*/
public <R> IterableUtils<R> map(final Class<R> returnType, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<R>(map(values, returnType, method));
}
/**
* apply the function to each element of Iterable with instance method.
*
* @param returnType returning type of {@code method}
* @param obj it has an provided {@code method}
* @param method method to apply
* @return new instance of IterableUtils - applied on each element
*/
public <R> IterableUtils<R> map(
final Class<R> returnType,
final Object obj,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<R>(map(values, returnType, obj, method));
}
/**
* filter elements of Iterable by provided function.
*
* @param method filtering method (* it must be returned {@code boolean} type *)
* @return new instance of filtered IterableUtils
*/
public IterableUtils<T> filter(final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<T>(filter(values, method));
}
/**
* filter elements of Iterable by provided function with instance method.
*
* @param obj it has an provided {@code method}
* @param method filtering method (* it must be returned {@code boolean} type *)
* @return new instance of filtered IterableUtils
*/
public IterableUtils<T> filter(final Object obj, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return new IterableUtils<T>(filter(values, obj, method));
}
/**
* call the provided function to each element of Iterable.
*
* @param method calling function
*/
public void forEach(final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
forEach(values, method);
}
/**
* call the provided function to each element of Iterable with instance method.
*
* @param obj it has an provided {@code method}
* @param method calling function
*/
public void forEach(final Object obj, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
forEach(values, obj, method);
}
/**
* apply the function to each element of Iterable to reduce it to a single value.
*
* @param initialValue first value of accumulator
* @param method it has two arguments and returned a value has type same as type of {@code initialValue}
*/
public <R> R reduce(final R initialValue, final Method method)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return reduce(values, initialValue, method);
}
/**
* apply the function to each element of Iterable to reduce it to a single value.
*
* @param obj it has an provided {@code method}
* @param initialValue first value of accumulator
* @param method it has two arguments and returned a value has type same as type of {@code initialValue}
*/
public <R> R reduce(
final Object obj,
final R initialValue,
final Method method
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return reduce(values, obj, initialValue, method);
}
/**
* returns {@code values}
*/
public Iterable<T> getValues() {
return values;
}
@SuppressWarnings("unchecked")
private static <T, R> R invokeMethod(
final Object obj,
final Method method,
final T value
) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
return (R)method.invoke(obj, value);
}
}
@htsign
Copy link
Author

htsign commented Dec 3, 2017

usage

import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

class Example {
    public static void main(String[] args) {
        // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 の ArrayList
        final List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 10; ++i) {
            list.add(Integer.valueOf(i));
        }
        
        try {
            final Method isEven = Example.class.getMethod("isEven", int.class);
            final Method stringValueOf = String.class.getMethod("valueOf", int.class);
            final Method println = PrintStream.class.getMethod("println", String.class);
            
            final Method plus = Example.class.getMethod("plus", int.class, int.class);
            
            // メソッドチェイン的な
            new IterableUtils<Integer>(list)          // IterableUtils インスタンスに変換
                .filter(isEven)                       // 2 で割り切れる数のみにフィルタ
                .map(String.class, stringValueOf)     // String 型にマッピング
                .forEach(System.out, println);        // 一つずつ System.out に出力 ==> 0, 2, 4, 6, 8
            
            // モジュールそのまま呼ぶ感じ
            // 畳み込んで合計
            System.out.println(IterableUtils.reduce(list, 0, plus));  // ==> 45
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static boolean isEven(int i) {
        return i % 2 == 0;
    }
    
    public static int plus(int lhs, int rhs) {
        return lhs + rhs;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment