Java 8个功能接口(Consumer)附加参数

Java 8 functional interface (Consumer) additional parameter

是否有可能以某种方式参数化 Java 8 消费者?我想要可重用的消费者,我可以在使用它的地方放置额外的参数。

List<DateTime> dates = new ArrayList<DateTime>();
Set<Alarm> alarms = new HashSet<Alarm>();

Consumer<Entry> entryConsumer1 = entry -> {
    LocalTime time = entry.getDate().toLocalTime();
    Alarm alarm = new Alarm(time, calendar1.getPattern());
    alarms.add(alarm);
    dates.add(entry.getDate());
};

Consumer<Entry> entryConsumer2 = entry -> {
    LocalTime time = entry.getDate().toLocalTime();
    Alarm alarm = new Alarm(time, calendar2.getPattern());
    alarms.add(alarm);
    dates.add(entry.getDate());
};

calendar1.generateEntries(criteria).forEach(entryConsumer1);
calendar2.generateEntries(criteria).forEach(entryConsumer2);

calendar1, calendar2 是同一类型

如您所见,两位消费者仅在一个论点上有所不同。是否可以简化此 code/don 不重复?

我们所做的是更改 API,虽然这不是一个简单的选项。

BiConsumer<String, Entry> entryConsumer = (pattern, entry) -> {
    LocalTime time = entry.getDate().toLocalTime();
    Alarm alarm = new Alarm(time, pattern);
    alarms.add(alarm);
    dates.add(entry.getDate());
};

并像这样调用 API(第一个参数传递给对 entryConsumer 的每次调用)

.forEach(calendar1.getPattern, entryConsumer);

但是,如果你不能改变API,你可以做的就是使用这样的方法。

calendar1.generateEntries(criteria).forEach(e -> entryConsumer(calendar1, e));
calendar2.generateEntries(criteria).forEach(e -> entryConsumer(calendar2, e));

public static void entryConsumer(Calendar cal, Entry e) {
    LocalTime time = entry.getDate().toLocalTime();
    Alarm alarm = new Alarm(time, cal.getPattern());
    alarms.add(alarm);
    dates.add(entry.getDate());
};

为您的消费者创建工厂方法:

public Consumer<Entry> createConsumer(Calendar calendar, Set<Alarm> alarms, List<DateTime> dates) {
    return entry -> {
        LocalTime time = entry.getDate().toLocalTime();
        Alarm alarm = new Alarm(time, calendar.getPattern());
        alarms.add(alarm);
        dates.add(entry.getDate());
    }
}

然后像这样使用它:

calendar1.generateEntries(criteria).forEach(createConsumer(calendar1, alarms, dates));
calendar2.generateEntries(criteria).forEach(createConsumer(calendar2, alarms, dates));

而且:使用具有副作用的 lambda 表达式或函数是不好的做法(违反函数式编程原则),例如向警报集添加警报或向 lambda 内的日期列表添加日期。一种更实用的方法是使用像 map 这样的转换方法,然后收集结果。例如:

Set<Alarm> alarms = calendar1.generateEntries(criteria)
    .map(entry -> new Alarm(entry.getDate().toLocalTime(), calendar1.getPattern()))
    .collect(Collectors.toSet());