我有一个方法,大约有十行代码。我想创建更多的方法来做完全相同的事情,除了一个会改变一行代码的小计算。这是一个传递函数指针来替换这一行的完美应用程序,但是Java没有函数指针。我最好的选择是什么?
当前回答
在Java 8之前,类似函数指针的功能最接近的替代品是匿名类。例如:
Collections.sort(list, new Comparator<CustomClass>(){
public int compare(CustomClass a, CustomClass b)
{
// Logic to compare objects of class CustomClass which returns int as per contract.
}
});
但现在在Java 8中,我们有一个非常简洁的替代方法,称为lambda表达式,它可以用作:
list.sort((a, b) -> { a.isBiggerThan(b) } );
其中isBiggerThan是CustomClass中的一个方法。我们也可以在这里使用方法引用:
list.sort(MyClass::isBiggerThan);
其他回答
你也可以这样做(在一些罕见的情况下是有意义的)。问题(这是一个大问题)是您失去了使用类/接口的所有类型安全性,并且您必须处理方法不存在的情况。
它确实有一个“好处”,即您可以忽略访问限制并调用私有方法(示例中没有显示,但您可以调用编译器通常不允许您调用的方法)。
同样,这在很少的情况下是有意义的,但在那些情况下,这是一个很好的工具。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main
{
public static void main(final String[] argv)
throws NoSuchMethodException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
final String methodName;
final Method method;
final Main main;
main = new Main();
if(argv.length == 0)
{
methodName = "foo";
}
else
{
methodName = "bar";
}
method = Main.class.getDeclaredMethod(methodName, int.class);
main.car(method, 42);
}
private void foo(final int x)
{
System.out.println("foo: " + x);
}
private void bar(final int x)
{
System.out.println("bar: " + x);
}
private void car(final Method method,
final int val)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
{
method.invoke(this, val);
}
}
新的Java 8函数接口和方法引用使用::操作符。
Java 8能够使用“@ Functional Interface”指针维护方法引用(MyClass::new)。不需要相同的方法名称,只需要相同的方法签名。
例子:
@FunctionalInterface
interface CallbackHandler{
public void onClick();
}
public class MyClass{
public void doClick1(){System.out.println("doClick1");;}
public void doClick2(){System.out.println("doClick2");}
public CallbackHandler mClickListener = this::doClick;
public static void main(String[] args) {
MyClass myObjectInstance = new MyClass();
CallbackHandler pointer = myObjectInstance::doClick1;
Runnable pointer2 = myObjectInstance::doClick2;
pointer.onClick();
pointer2.run();
}
}
那么,我们得到了什么?
function Interface——这是一个接口,无论是否带有@FunctionalInterface注释,它只包含一个方法声明。 方法引用-这只是特殊的语法,看起来像这样,objectInstance::methodName,不多不少。 用法示例-只是一个赋值操作符,然后调用接口方法。
您应该仅为侦听器使用函数接口,而且仅用于侦听器!
因为所有其他类似的函数指针都不利于代码的可读性和理解能力。然而,直接方法引用有时很方便,例如foreach。
有几个预定义的功能接口:
Runnable -> void run( );
Supplier<T> -> T get( );
Consumer<T> -> void accept(T);
Predicate<T> -> boolean test(T);
UnaryOperator<T> -> T apply(T);
BinaryOperator<T,U,R> -> R apply(T, U);
Function<T,R> -> R apply(T);
BiFunction<T,U,R> -> R apply(T, U);
//... and some more of it ...
Callable<V> -> V call() throws Exception;
Readable -> int read(CharBuffer) throws IOException;
AutoCloseable -> void close() throws Exception;
Iterable<T> -> Iterator<T> iterator();
Comparable<T> -> int compareTo(T);
Comparator<T> -> int compare(T,T);
对于早期的Java版本,您应该尝试Guava库,正如Adrian Petrescu上面提到的,它具有类似的功能和语法。
如需进一步研究,请参阅Java 8 Cheatsheet
感谢戴帽子的家伙提供的Java语言规范§15.13链接。
谷歌Guava库正在变得非常流行,它有一个通用的Function和Predicate对象,它们已经在API的许多部分中使用了这些对象。
我觉得这是个策略模式。查看fluffycat.com Java模式。
你可能也会对Java 7中涉及闭包的工作感兴趣:
Java闭包的当前状态是什么?
http://gafter.blogspot.com/2006/08/closures-for-java.html http://tech.puredanger.com/java7/#closures
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap