首页 > 解决方案 > Java 方法引用实例化

问题描述

我正在尝试构建一个库,您可以在其中添加和删除发布/订阅系统中事件的侦听器,但使用方法引用时遇到了问题:

// here, this::printMessage is being passed as an instance of Consumer<String>
pubSub.subscribe(this::printMessage);
pubSub.unsubscribe(this::printMessage);

在内部,调用subscribe()会将 的实例添加Consumer<T>到 a Set<Consumer<T>>unsubscribe()并将其删除。这个问题源于这样一个事实,即this::printMessage此处的每次使用实际上都会导致编译器生成一个新的对象引用/实例,因此,取消订阅实际上不起作用。

到目前为止,我管理的解决方法是:

final Consumer<String> consumer = this::printMessage;
pubSub.subscribe(consumer);
pubSub.unsubscribe(consumer);

但是,这并不理想。我担心使用此库的经验不足的人可能会假设他们可以在订阅/取消订阅时直接使用方法引用,而事实并非如此,最坏的情况会导致内存泄漏。

所以问题是,是否有一些巧妙的方法可以避免这种情况或强制方法引用始终解析为相同的对象引用/实例?

标签: javamethod-reference

解决方案


You could make subscribe either return the actual Consumer instance or an identifier for the added Consumer. This return value could be used in unsubscribe to remove the Consumer again.

Maybe something similar to this:

Map<UUID, Consumer<?>> consumers = new ConcurrentHashMap<>();

public UUID subscribe(Consumer<?> consumer) {
    UUID identifier = UUID.randomUUID();
    consumers.put(identifier, consumer);
    return identifier;
}

public void unsubscribe(UUID identifier) {
    consumers.remove(identifier);
}

The usage of an identifier instead of the actual Consumer instance as return value has the advantage that users of your code will directly see that they need to keep track of the returned UUID instead of using unsubscribe with a different 'identical' (in terms of behavior) Consumer.


推荐阅读