在underscore.js中有一个debounce函数,其入参有两个,第一个是函数F1,第二个是时间T,返回值是另一个函数F2。
F2的作用是调用F1,但是有一个限制:一个F2被调用之后T时间内,如果F2再一次被调用,那么第一次F2调用的F1会被取消,第二次F2的F1是否被调用,取决于T时间内是否有第三次F2调用。
由于closure存在,underscore.js的实现其实很简单,可以参考underscore.js源码。于是我突发奇想,Java中如果要实现这样一个函数,应该怎么实现呢?
首先,Java不允许传递函数,取而代之用FuntionalInterface代替,返回值也是一个FunctionalInterface,暂时使用Consumer来代替。
package aac.java.debounce;
import java.util.function.Consumer;
public class FuncUtil {
public static <T> Consumer<T> debounce(Consumer<T> consumer, Long milliSeconds) {
return new Consumer<T>() {
Thread threads[] = {null};
@Override
public void accept(T t) {
if(threads[0] != null) {
threads[0].interrupt();
}
threads[0] = new Thread(() -> {
try {
//首先sleep一段时间,然后执行函数
Thread.sleep(milliSeconds);
consumer.accept(t);
threads[0] = null;
} catch (InterruptedException e) {
//如果中途被interrupt就不执行函数
}
});
threads[0].start();
}
};
}
}
调用方式如下:
Consumer<Object> consumer = FuncUtil.debounce(System.out::println, 1000L);
consumer.accept(1);
Thread.sleep(1001L);
consumer.accept(2);
consumer.accept(3);
consumer.accept(4);
可以看出最终只输出了一次4。
如果调用方式如下:
consumer.accept(1);
Thread.sleep(1001L);
consumer.accept(2);
consumer.accept(3);
consumer.accept(4);
那么会输出1和4,可以看出目的达到了。
其实实现的思路很简单,就是要把上一次函数调用记录下来。如果下一次调用的时候线程还在,那么就把调用的线程取消掉。
这个实现方法的弊端在于Java的函数并不像JavaScript一样灵活,Java是强类型的语言,不能够入参不能够像JavaScript一样是任意类型的函数,那么如何解决这个问题呢?而且即使入参能够是任何类型函数,那么返回值用什么来接收呢?
我暂时还没有想到解决方案,但是一个比较可行的解决方案是使用下面这样的函数签名:
Object fun(Object ... objects)
这样应该可以解决函数传入和return的问题,但是不够优雅,如果我之后想到了什么好的解决方法,我会在这篇文章中更新。
网友评论