foreach in Java
Here’s a cool but unfortunately useless example of Java generics, combined with reflection, combined with dynamic proxies.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
import sun.reflect.generics.tree.ReturnType;
public class Foreach {
@SuppressWarnings("unchecked")
public static <T> T foreach(T... elements) {
ApplyOnArrray<T> handler = new ApplyOnArrray<T>(elements);
return (T) Proxy.newProxyInstance(elements[0].getClass().getClassLoader(),
new Class[] { elements[0].getClass().getInterfaces()[0] },
handler);
}
public static <ReturnType> List<ReturnType> get(ReturnType returnValue) {
Collector collector = (Collector) Proxy.getInvocationHandler(returnValue);
return collector.getReturnValues();
}
public static void main(String[] args) {
IFoo f1 = new Foo();
IFoo f2 = new Foo();
IFoo f3 = new Foo();
IFoo f4 = new Foo();
List<IString> list = get(foreach(f1, f2, f3, f4).sayFoo());
System.out.println(list);
}
}
class Collector implements InvocationHandler {
private final List returnValues;
public Collector(List returnValues) {
this.returnValues = returnValues;
}
public List getReturnValues() {
return returnValues;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO get(foreach(elements).method(args))
throw new NotImplementedException();
}
}
interface IString { String toString(); }
class StringImpl implements IString {
private String s;
public StringImpl(String s) { this.s = s; }
public String toString() { return s; }
}
interface IFoo { IString sayFoo(); };
class Foo implements IFoo {
public IString sayFoo() {
System.out.println("foo");
return new StringImpl("foo");
}
};
class ApplyOnArrray<T> implements InvocationHandler {
private final T[] elements;
public ApplyOnArrray(T... elements) { this.elements = elements; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method targetMethod = elements[0].getClass().getMethod(method.getName(), method.getParameterTypes());
List returnValues = new ArrayList();
for (T element : elements) returnValues.add(targetMethod.invoke(element, args));
// return a proxy for the result
return (T) Proxy.newProxyInstance(elements[0].getClass().getClassLoader(),
new Class[] { targetMethod.getReturnType() },
new Collector(returnValues));
}
} I had this idea in a dream (too much work) and fortunately I could still remember it in the morning. Who knows, I might have dreamt also a solution that works with classes.