public void Main(){
//在这里定义代码块,并传入 Test 方法里
Test(
delegate(){
//代码逻辑
}
);
}
public void Test(dele a)
{
invoke(a);////在这里执行传入的代码块
}
这种写法类似 C#到委托,java 里能做到吗?
1
yikuo 2020-04-27 20:37:50 +08:00 via Android 1
可以传递一个 Runnable 对象
|
2
xizismile 2020-04-27 20:45:16 +08:00 via Android
方式 1:用对象来包装逻辑传递给其它方法
方式 2:用 java8 提供的函数式接口来实现 |
3
xiangyuecn 2020-04-27 20:48:04 +08:00
delegate ? C#打死也不用这么难懂的玩意(主要是这个单词手写敲不出来),还不如定义一个 interface 来的统一实在。。。实际上还是 Action 、Func 随便定义随便用,随便当参数,虽然本质上还是 delegate
java:interface,统一实在,没参数的用 Runnable 省去了一个 interface 定义 |
4
KentY 2020-04-27 20:59:30 +08:00
java 的源代码需要编译才能在 jvm 里执行. 所以你不能传递一个动态的 string, 然后希望 java 执行它.
java 可以动态读取源代码文件并编译成 class, 比如通过 JavaCompiler 编译, 然后再通过 reflection 执行编译好的 class 里的 method.但是我猜这不是你需要的. 如果我没理解错的话, 你大概需要一个类似 callback 的东西, 如果 java 版本是 8+, 它提供了一些现成的接口, 也可以就定义一个 classFooCallback {delegate(){...}}, 然后传递 FooCallback fooCallback instead of "dele a" . 当执行的时候, fooCallback.delegate()就可以了. 按一般来说, 你的 delegate method 需要参数, 否则意义不大. |
5
chihiro2014 2020-04-27 21:00:39 +08:00
可以传逻辑,例如使用 Function
|
6
6IbA2bj5ip3tK49j 2020-04-27 21:02:00 +08:00
这不就是传个函数进去吗……
|
7
atfeel OP @xiangyuecn interface 不灵活,还要定义,麻烦啊
|
8
MineDog 2020-04-27 21:15:28 +08:00 via Android
lambda 表达式啊,前提是要函数式接口
|
9
luckyrayyy 2020-04-27 21:15:42 +08:00
完全,可能你得自己做一些工作。你可以动态生成一个 class 然后执行,直接执行代码块的话就不太确定行不行了。
|
10
xiangyuecn 2020-04-27 21:23:59 +08:00
@atfeel #7 不会,无参的直接用系统的 Runnable 不用定义。有参的自己写个,大不了参数全为 Object😂
interface Func<T>{ void fn(T...args); //Type safety: Potential heap pollution via varargs parameter args😂 这坨带码只是意思意思 } . . . 先定义几个全局通用的。要什么参数的、返回值的类里面直接嵌套定义,哪里要就定义到哪里 |
11
ipwx 2020-04-27 21:39:26 +08:00
Java 8 不是有语法糖么,配合 interface 可以 f(x -> x + 1) 之类的
|
12
ipwx 2020-04-27 21:39:53 +08:00 1
不过我记得 java 8 lambda 最大的问题不是有没有语法糖,而是 exception 检查那套。。。
|
13
atfeel OP @xiangyuecn 你的方法看起来不错,能随便写个模型我看看吗,分水岭难于逾越
谢谢 |
14
Febers 2020-04-27 21:46:31 +08:00
遇到过同样的需求,在没有改写成 Kotlin 之前,使用的是 Runnable 然后手动调 run ;改写成 Kotlin 之后看起来还挺酷的:
//定义 var action: ()->Unit = { } //赋值 action = { //some code } //调用 action.invoke() //action() |
15
xiangyuecn 2020-04-27 21:56:19 +08:00
#13 没格式,自己格式化一下再看
static class aaa{ static void exec(Func<Integer, Boolean, String> func1, Runnable action1, Action<String,Object,Integer> action2) { String val=func1.call(123, true); action1.run(); action2.call(val, new java.util.Date(), 456); } interface Action<T1,T2,T3>{ void call(T1 a1,T2 a2,T3 a3); } interface Func<T1, T2, ReturnType>{ ReturnType call(T1 a1,T2 a2); } static public void test() { exec(new Func<Integer, Boolean, String>(){ @Override public String call(Integer a1, Boolean a2) { return a1+" "+a2; } },new Runnable() { @Override public void run() { System.out.println("Runnable"); } },new Action<String, Object, Integer>() { @Override public void call(String a1, Object a2, Integer a3) { System.out.println(a1+" "+a2+" "+a3); } }); } } |
16
liyanggyang 2020-04-28 09:41:19 +08:00 2
Consumer<T>:消费型接口(有钱咱就花)
接收一个数据,并且处理这个数据,处理完成之后, 不需要返回任何数据,直接输出 con.accept(); Supplier<T>:供给型接口(后勤) 提供需要用到的数据 sup.get(); Function<T, R>:函数型接口(乾坤大挪移) 接收 T 类型转换为 R 类型 fun.apply(); Predicate<T>:断言型接口(包公断案) 判断对与错,把控 if 关卡 |
17
lff0305 2020-04-28 10:04:17 +08:00
Java 有很多 Runtime Compiler, 比如 logback 在用的 Janino, 等等
以前实现类似的功能用的是 JDK8 里带的 js 引擎, js 当字符串传过去 eval 就 OK |
18
Jrue0011 2020-04-28 10:19:16 +08:00
JDK8 以后 java.util.function 下的接口基本能满足大部分日常需求了
|
20
atfeel OP @xiangyuecn 感谢
|
23
gz233 2020-04-28 10:58:12 +08:00
@liyanggyang 正解
|
24
no1xsyzy 2020-04-28 11:19:12 +08:00
感觉没什么分水岭的,只要你不是动态逻辑(即执行的代码是编译时决定的),那就可以用对象实现闭包,甚至如果不需要闭包就传个匿名类就行。
至于需要动态逻辑、动态构造代码并执行的,那需要重新来套 lexer, syntaxer, interpreter/compiler 等,而且手动拼装语句容易错,如果是远程给代码直接调用,不如直接用个 JVM 内的解释器。 或者含泪实践格林斯潘第十定律。 |
25
Febers 2020-04-28 12:03:49 +08:00
@atfeel #22
Kotlin 代码的本质是,定义一个类型属于 () -> Unit 的变量,然后动态赋值,通过 invoke 方法执行,反编译 Kotlin 的字节码之后可以发现,其对应的 Java 类型是 Function0 接口,位于 kotlin.jvm.functions,仿照其写法 //使用了 @FunctionalInterface 以使用 Lambda @FunctionalInterface interface Action { void invoke(); } //定义与赋值 Action action; action = () -> { //some code 1 }; //非 Lambda 写法 action = new Action() { @Override public void invoke() { //some code 2 } }; //调用 action1.invoke(); 使用 Runnable 的原因很简单,它是系统定义的一个 FunctionalInterface,而且很普通,调用 run 方法也跟多线程没有关系,把 Runnable 替换成上面的 Action,就可以少写一个接口 |
26
Febers 2020-04-28 12:14:40 +08:00 1
个人觉得 Kotlin 的很多东西很有趣,学习 Kotlin 反编译之后的 Java 代码,基本上就是用 Java 如何实现 Kotlin 特性的工业化答案。
这个问题很多同学都给了答案,重点在于:Java 是纯面向对象语言,一切方法参数都是对象(基本数据类型不谈),而匿名内部类的存在让我们可以使用 自定义方法的对象,虽然写法看起来比较啰嗦;引入 Lambda 之后的 Java 代码写起来更“函数式”了,但本质上还是使用对象的概念 |
27
Febers 2020-04-28 12:21:33 +08:00
如果要深究到语言特性的话,对于这样的需求,Java 字节码层面支持是 invokedynamic 指令的引入,语法层面的支持是 Lambda 的引入
|
30
zclHIT 2020-04-28 13:03:38 +08:00
functional interface
|
31
no1xsyzy 2020-04-28 13:11:47 +08:00
@Febers #29 Java 7 的时候 Callback 的写法只有这样吧…… 我 Java 用得不多,也是老早的事了,GUI 的 handler 就差不多只能这么玩,哪像 Qt 用槽。
|
32
sandrew1945 2020-04-28 13:21:37 +08:00
使用 Lambda,参考 vert.x
``` vertx.executeBlocking(this::blockingCode, this::resultHandler); private void blockingCode(Promise<JsonObject> promise) { // do something } private void resultHandler(AsyncResult<JsonObject> ar) { // get result } ``` 其中 executeBlocking 是这样定义的 ``` <T> void executeBlocking(Handler<Promise<T>> var1, Handler<AsyncResult<T>> var2); public interface Handler<E> { void handle(E var1); } ``` |
33
aguesuka 2020-04-28 13:50:44 +08:00 via Android
effctive java 3rd 44 优先使用标准的函数式接口
|
34
CoderGeek 2020-04-28 14:45:43 +08:00
Functional
|
35
stevenkang 2020-04-28 14:48:12 +08:00
推荐文章 [Java8 新特性学习-函数式编程]( https://blog.csdn.net/icarusliu/article/details/79495534)
|
36
gmywq0392 2020-04-28 14:59:26 +08:00
exec
|
38
kingiis 2020-04-29 14:10:18 +08:00
你是想问 动态生成 java 代码 动态执行么
不如切到 js 动态 js 倒是很容易 |