http://stackoverflow.com/questions/1184418/javas-equivalents-of-func-and-action
http://stackoverflow.com/questions/1340231/equivalent-of-c-sharp-anonymous-delegates-in-java
http://stackoverflow.com/questions/44912/java-delegates
问题:
In C#, you can define small pieces of code called delegates anonymously (even though they are nothing more than syntactic sugar). So, or example, I can do this:
------------------------------------------------------------------------------------
public string DoSomething(Func<string, string> someDelegate){
// Do something involving someDelegate(string s)
}
DoSomething(delegate(string s){ return s += "asd"; });
DoSomething(delegate(string s){ return s.Reverse(); });
------------------------------------------------------------------------------------
Is it possible to pass code like this in Java? I'm using the processing framework, which has a quite old version of Java (it doesn't have generics).
答案:
Pre Java 8:
The closest Java has to delegates are single method interfaces. You could use an anonymous inner class.
------------------------------------------------------------------------------------
interface StringFunc {
String func(String s);
}
void doSomething(StringFunc funk) {
System.out.println(funk.func("whatever"));
}
doSomething(new StringFunc() {
public String func(String s) {
return s + "asd";
}
});
doSomething(new StringFunc() {
public String func(String s) {
return new StringBuffer(s).reverse().toString();
}
});
------------------------------------------------------------------------------------
Java 8 and above:
Java 8 adds lambda expressions to the language.
------------------------------------------------------------------------------------
doSomething((t) -> t + "asd");
doSomething((t) -> new StringBuilder(t).reverse().toString());
------------------------------------------------------------------------------------
C#中拥有Action和Func,而Java到java 8才有类似的东西。
------------------------------------------------------------------------------------
Action<T> Delegate
Func<T, TResult> Delegate
------------------------------------------------------------------------------------
比如一个例子(http://msdn.microsoft.com/en-us/library/bb549151.aspx)
------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
static class Func
{
static void Main(string[] args)
{
// Declare a Func variable and assign a lambda expression to the
// variable. The method takes a string and converts it to uppercase.
Func<string, string> selector = str => str.ToUpper();
// Create an array of strings.
string[] words = { "orange", "apple", "Article", "elephant" };
// Query the array and select strings according to the selector method.
IEnumerable<String> aWords = words.Select(selector);
// Output the results to the console.
foreach (String word in aWords)
Console.WriteLine(word);
}
}
/*
This code example produces the following output:
ORANGE
APPLE
ARTICLE
ELEPHANT
*/
------------------------------------------------------------------------------------
http://msdn.microsoft.com/en-us/library/018hxwa8.aspx
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<String>();
names.Add("Bruce");
names.Add("Alfred");
names.Add("Tim");
names.Add("Richard");
// Display the contents of the list using the Print method.
names.ForEach(Print);
// The following demonstrates the anonymous method feature of C#
// to display the contents of the list to the console.
names.ForEach(delegate(String name)
{
Console.WriteLine(name);
});
}
private static void Print(string s)
{
Console.WriteLine(s);
}
}
/* This code will produce output similar to the following:
* Bruce
* Alfred
* Tim
* Richard
* Bruce
* Alfred
* Tim
* Richard
*/
------------------------------------------------------------------------------------
但是可以模拟
------------------------------------------------------------------------------------
Callable interface is similar to Func.
Runnable interface is similar to Action
------------------------------------------------------------------------------------
下面是Steve Lewisd的一个实现
------------------------------------------------------------------------------------
http://onjava.com/pub/a/onjava/2003/05/21/delegates.html
package com.lordjoe.csharp;
import java.lang.reflect.*;
import java.util.List;
import java.util.ArrayList;
/**
* com.lordjoe.csharp.Delegator Class representing a delegate tamplate - also a
* factory treturning the real delegate object
*
* @author Steve Lewis [email protected]
*/
public class Delegator {
public static final Method[] EMPTY_METHOD_ARRAY = {};
public static final Object[] EMPTY_OBJECT_ARRAY = {};
public static final Delegator[] EMPTY_ARRAY = {};
// convenience implementation
public static final Delegator RUNNABLE_DELEGATE = new Delegator(
Runnable.class);
/**
* Convenience method to make a runnable delegate
*
* @param item
* non-null target object
* @param methodName
* non-null name of a method of type void ()
* @return non-null Runnable proxy
*/
public static Runnable buildRunnable(Object item, String methodName) {
return ((Runnable) RUNNABLE_DELEGATE.build(item, methodName));
}
/**
* Convenience method to make a runnable delegate
*
* @param item
* non-null target class
* @param methodName
* non-null name of a method of type void ()
* @return non-null Runnable proxy
*/
public static Runnable buildRunnable(Class item, String methodName) {
return ((Runnable) RUNNABLE_DELEGATE.build(item, methodName));
}
private final Class m_Interface; // may be null
private final Class m_Return;
private final Class[] m_Arguments;
/**
* 代理参数为params,返回值为retClass,没有接口的类型
* @param params
* non-null array of arguments
* @param retClass
* possibly null return class null says do not care
*/
public Delegator(Class[] params, Class retClass) {
m_Interface = null;
m_Return = retClass;
m_Arguments = params;
}
/**
* 代理只有个方法的接口
* @param TheInterface
* an non-null interface with EXACTLY one method
*/
public Delegator(Class TheInterface) {
m_Interface = TheInterface;
Method met = findMethod(TheInterface);
m_Return = met.getReturnType();
m_Arguments = met.getParameterTypes();
}
/**
* accessor for return class
*/
public Class getReturn() {
return m_Return;
}
/**
* accessor for argument classes
*/
public Class[] getArguments() {
return m_Arguments;
}
public Class getInterface() {
return m_Interface;
}
/**
*
* @param target
* non-null class with a bindable static method
* @param MethodName
* name of the static method
* @return non-null IDelegate if getInterface() is non-null it will be a
* dynamic prozy implementing that interface
*/
public IDelegate build(Class target, String MethodName) {
Class myInterface = getInterface();
DelegateProxy theDelegate = new DelegateProxy(null, target, MethodName,
this);
if (myInterface != null) {
Class[] interfaces = { myInterface, IDelegate.class };
IDelegate ret = (IDelegate) java.lang.reflect.Proxy
.newProxyInstance(target.getClassLoader(), interfaces,
theDelegate);
return (ret);
}
return ((IDelegate) theDelegate);
}
/**
*
* 通过一个对象和它的方法名创建一个代理对象
* @param target
* non-null target with a bindable method
* @param MethodName
* name of the method
* @return non-null IDelegate if getInterface() is non-null it will be a
* dynamic prozy implementing that interface
*/
public IDelegate build(Object target, String MethodName) {
Class myInterface = getInterface();
DelegateProxy theDelegate = new DelegateProxy(target,
target.getClass(), MethodName, this);
if (myInterface != null) { // build a dynamic proxy
Class[] interfaces = { myInterface, IDelegate.class };
IDelegate ret = (IDelegate) java.lang.reflect.Proxy
.newProxyInstance(target.getClass().getClassLoader(),
interfaces, theDelegate);
return (ret);
}
if (!(theDelegate instanceof IDelegate))
throw new ClassCastException();
return ((IDelegate) theDelegate);
}
protected class DelegateProxy implements IDelegate, InvocationHandler {
private final Method m_Method;
private final Object m_Target;
private final Delegator m_Template;
/**
* constructor supplying a Class passing in types not template
*
* @param target
* possibly null target if null the method must be static
* @param target
* non-null class implementing a suitable method
* @param target
* non-null object implementing a suitable static method
* @param MethodName
* nun-null name of a public static method in target
* @param template
* non-null template with the required arguemts and return
*/
protected DelegateProxy(Object target, Class targetClass,
String MethodName, Delegator template) {
m_Template = template;
m_Target = target;
Method meth = findSuitableMethod(targetClass, MethodName, template);
m_Method = meth;
}
/**
* convenience call to handle case of no arguments
*
* @return whatever is returned
*/
public Object invoke() throws IllegalArgumentException,
DelegateInvokeException {
return (invoke(EMPTY_OBJECT_ARRAY));
}
/**
* convenience call to handle case of one argument
*
* @param arg
* some argument
* @return whatever is returned
*/
public Object invoke(Object arg) throws IllegalArgumentException,
DelegateInvokeException {
Object[] args = { arg };
return (invoke(args));
}
/**
* convenience call to handle case of two argument
*
* @param arg1
* some argument
* @param arg2
* some argument
* @return whatever is returned
*/
public Object invoke(Object arg1, Object arg2)
throws IllegalArgumentException, DelegateInvokeException {
Object[] args = { arg1, arg2 };
return (invoke(args));
}
/**
* method required by InvocationHandler so we can build dynamic Proxys
*
* @param proxy
* object for which we are a proxy (ignored)
* @param method
* method to call (ignored)
* @param args
* arguments to pass
* @return whatever is returned primitive types are wrapped
*/
public Object invoke(Object proxy, Method method, Object[] args) {
return (invoke(args));
}
/**
* basic call to method
*
* @param args
* method arguments
* @return whatever is returned
*/
public Object invoke(Object[] args) throws IllegalArgumentException,
DelegateInvokeException {
// validateArgs(args);
try {
Object ret = getMethod().invoke(getTarget(), args);
return (ret);
} catch (IllegalAccessException ex1) {
throw new IllegalStateException("Bad Delgate State"
+ ex1.getMessage()); // should not happen
} catch (InvocationTargetException ex1) {
throw new Delegator.DelegateInvokeException(ex1.getCause());
}
}
/**
* if uncommented in invoke this code will throw an IllegalArgument call
* if arguments are of the wrong type
*/
protected void validateArgs(Object[] args)
throws IllegalArgumentException {
Class[] MyArgs = getArguments();
if (args.length != MyArgs.length)
throw new IllegalArgumentException("Delegate required "
+ MyArgs.length + "arguments");
for (int i = 0; i < args.length; i++) {
if (!MyArgs[i].isInstance(args[i]))
throw new IllegalArgumentException("Argument " + i
+ " must be of class " + MyArgs[i].getName());
}
}
/**
* accessor for the method
*/
public Method getMethod() {
return m_Method;
}
/**
* accessor for the target
*/
public Object getTarget() {
return m_Target;
}
}// end class DelegateProxy
/**
* All problems become this type of exception As a runtime we do not impose
* burdens on the calling code
*/
public static class DelegateInvokeException extends RuntimeException {
public DelegateInvokeException(Throwable cause) {
super(cause);
}
}
// ===================================================================
// static utility methods in this section identify the
// method in verious targets
// ===================================================================
/**
* utility method to test suitability
*/
protected static boolean isSuitableMethod(Method testMethod, Class[] args,
Class retClass) {
Class[] methodArgs = testMethod.getParameterTypes();
for (int i = 0; i < methodArgs.length; i++) {
Class arg = methodArgs[i];
if (!arg.isAssignableFrom(args[i]))
return (false);
}
// This is the only
isValidReturn(testMethod, retClass);
return (true);
}
/**
* utility method to get candidate methods to search
*/
protected static Method[] getCandidateMethods(Class targetClass,
String MethodName, int nargs) {
Method[] possibilities = targetClass.getMethods();
List holder = new ArrayList();
for (int i = 0; i < possibilities.length; i++) {
Method possibility = possibilities[i];
if (possibility.getName().equals(MethodName)
&& possibility.getParameterTypes().length == nargs
&& Modifier.isPublic(possibility.getModifiers()))
holder.add(possibility);
}
return ((Method[]) holder.toArray(EMPTY_METHOD_ARRAY));
}
/**
* utility method to test return
*/
protected static boolean isValidReturn(Method test, Class retClass) {
if (retClass == null)
return (true); // we do not care
if (test.getReturnType() == retClass)
return (true);
if (retClass.isAssignableFrom(test.getReturnType()))
return (true);
return (false);
}
/**
* Utility method to locate a proper Method object
* 从targetClass中找到合适的方法(f返回值和参数必须匹配)
*/
protected static Method findSuitableMethod(Class targetClass,
String MethodName, Delegator templ) {
Class[] args = templ.getArguments();
Class retClass = templ.getReturn();
// perfect match
try {
Method ret = targetClass.getMethod(MethodName, args);
if (!isValidReturn(ret, retClass))
throw new IllegalArgumentException(
"Requested method returns wrong type");
if (!Modifier.isPublic(ret.getModifiers()))
throw new IllegalArgumentException(
"Requested method is not public");
return (ret);
} catch (Exception ex) {
} // on to try2
Method[] possibilities = getCandidateMethods(targetClass, MethodName,
args.length);
for (int i = 0; i < possibilities.length; i++) {
Method possibility = possibilities[i];
if (isSuitableMethod(possibility, args, retClass))
return (possibility);
}
throw new IllegalArgumentException("No suitable method found");
}
/**
* utility code to find the one suitable method in the passed in interface.
* 找到接口中唯一的方法
*/
protected static Method findMethod(Class TheInterface) {
if (!TheInterface.isInterface())
throw new IllegalArgumentException(
"DelegateTemplate must be constructed with an interface");
Method[] methods = TheInterface.getMethods();
Method ret = null;
for (int i = 0; i < methods.length; i++) {
Method test = methods[i];
if (Modifier.isAbstract(test.getModifiers())) {
if (ret != null)
throw new IllegalArgumentException(
"DelegateTemplate must be constructed "
+ " with an interface implementing only one method!");
ret = test;
}
}
if (ret == null)
throw new IllegalArgumentException(
"DelegateTemplate must be constructed "
+ " with an interface implementing exactly method!");
return (ret);
}
}
------------------------------------------------------------------------------------
package com.lordjoe.csharp;
/**
* Interface implemnted by the object returned by Delegator.bind
* Use this only when no suitable alternative interface is available
* @author Steve Lewis
* Date: May 9, 2002
**/
public interface IDelegate {
/**
* Thin wrapper in invoke
* @param args possibly null array or args - null says none
* @return possibly null return - primitive types are wrapped
*/
public Object invoke(Object[] args);
/**
* convenience call for 1 arg case
* @param arg possibly null argument
* @return possibly null return - primitive types are wrapped
*/
public Object invoke(Object arg);
/**
* convenience call for 2 arg case
* @param arg1 possibly null argument
* @param arg2 possibly null argument
* @return possibly null return - primitive types are wrapped
*/
public Object invoke(Object arg1, Object arg2);
/**
* convenience call for no arg case
* @return possibly null return - primitive types are wrapped
*/
public Object invoke();
}
------------------------------------------------------------------------------------
package com.lordjoe.csharp;
import junit.framework.*;
/**
* com.lordjoe.csharp.TestDelegate2
*
* @author Steve Lewis [email protected]
*/
public class TestDelegate extends TestCase {
public static final int ITER_COUNT = 10 * 1000 * 1000;
/**
* common interface - note No implementing class i.e. Class1 implements this
*/
public static interface IStringDisplay {
public void doDisplay(String s);
}
public TestDelegate(String name) {
super(name);
}
/**
* This section tests that DelegateTemplate fails when passed an unsuitable
* interface
*/
public static interface IBadStringDisplay {
public void doDisplay(String s);
public void doDisplay2(String s);
}
public static interface IBadStringDisplay2 {
}
public void testDelegateBuild() {
try {
//有两个方法,失败
new Delegator(IBadStringDisplay.class);
fail();
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
//DelegateTemplate must be constructed with an interface implementing only one method!
}
try {
//IBadStringDisplay2没有方法,失败
new Delegator(IBadStringDisplay2.class);
fail();
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
//DelegateTemplate must be constructed with an interface implementing exactly method!
}
}
/**
* code to test calls to delegate
*/
public void testDelegate() throws Exception {
Delegator myDelegate = new Delegator(IStringDisplay.class);
Class1 obj1 = new Class1();
Class2 obj2 = new Class2();
IStringDisplay[] items = new IStringDisplay[3];
items[0] = (IStringDisplay) myDelegate.build(obj1, "show");
items[1] = (IStringDisplay) myDelegate.build(obj2, "display");
items[2] = (IStringDisplay) myDelegate.build(Class3.class,
"staticDisplay");
for (int i = 0; i < items.length; i++) {
IStringDisplay item = items[i];
item.doDisplay("test");
}
/**
* ==>doDisplay调用InvocationHandler(DelegateProxy)的invoke方法
* ==>在invoke方法中的调用display、show、staticDisplay等方法,并且将doDisplay才参数传递进去
*/
// timingTest(items,obj1,obj2,ITER_COUNT);
}
/**
* code to test calls to delegate
*/
public void testDelegateInvoke() throws Exception {
Class[] params = { String.class };
Delegator myDelegate = new Delegator(params, Void.TYPE);
Class1 obj1 = new Class1();
Class2 obj2 = new Class2();
IDelegate[] items = new IDelegate[3];
items[0] = myDelegate.build(obj1, "show");
items[1] = myDelegate.build(obj2, "display");
items[2] = myDelegate.build(Class3.class, "staticDisplay");
for (int i = 0; i < items.length; i++) {
IDelegate item = items[i];
item.invoke("test");
}
//静态代理
}
/**
* Test of timing - note set iteration large i.e. 1000000 for resaonbale
* results
*/
public void timingTest(IStringDisplay[] items, Class1 obj1, Class2 obj2,
int iterations) {
// Warm up hotspot
for (int k = 0; k < 100; k++) {
for (int i = 0; i < items.length; i++) {
IStringDisplay item = items[i];
item.doDisplay("test");
}
obj1.show("test");
obj2.display("test");
Class3.staticDisplay("test");
}
long start = System.currentTimeMillis();
for (int j = 0; j < iterations; j++) {
for (int i = 0; i < items.length; i++) {
IStringDisplay item = items[i];
item.doDisplay("test");
}
}
long end = System.currentTimeMillis();
double delegateTime = (end - start) / 1000;
double perIteration = 1000 * 1000 * delegateTime / iterations;
start = System.currentTimeMillis();
for (int j = 0; j < iterations; j++) {
obj1.show("test");
obj2.display("test");
Class3.staticDisplay("test");
}
end = System.currentTimeMillis();
double directTime = (end - start) / 1000;
double perCallIteration = 1000 * 1000 * directTime / iterations;
System.out.println("Ran " + iterations + " iterations ");
System.out.println("Delegate Test took " + delegateTime + "sec");
System.out.println("per iteration " + perIteration + "microsec");
System.out.println("Direct Calls took " + directTime + "sec");
System.out.println("per iteration " + perCallIteration + "microsec");
}
public static Test suite() {
return new TestSuite(TestDelegate.class);
}
public static void main(String[] args) {
String[] RealArgs = { "com.lordjoe.csharp.TestDelegate3" };
// junit.swingui.TestRunner.main(RealArgs);
junit.textui.TestRunner.main(RealArgs);
}
}
/**
* some classes we need to call method body might printout fir vicibility or
* increment a variable for timing test (to prevent optimizing out)
*/
class Class1 {
int count;
public void show(String s) {
count++; // System.out.println(s);
System.out.println("Class3 show " +s+" "+count);
}
}
class Class2 {
int count;
public void display(String s) {
count++;// System.out.println(s);
System.out.println("Class2 display " +s+" "+count);
}
}
/**
* here the methos is static
*/
class Class3 { // allows static method as well
static int count;
public static void staticDisplay(String s) {
count++; // System.out.println(s);
System.out.println("Class3 staticDisplay " +s+" "+count);
}
}
------------------------------------------------------------------------------------