在Java中实现debounce函数

在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  Consumer debounce(Consumer consumer, Long milliSeconds) {
        return new Consumer() {
            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 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的问题,但是不够优雅,如果我之后想到了什么好的解决方法,我会在这篇文章中更新。

你可能感兴趣的:(在Java中实现debounce函数)