How to send parameters to a reference method in a stream (java 8)?

我与影子孤独终老i 提交于 2020-02-22 08:12:21

问题


I have a list of activities(Activity) and I want to determine a data structure of the form Map(String, DateTime) (not Duration or Period; DateTime it's a must) that maps. For each activity the total duration computed over the monitoring period.

The class Activity has: activityLabel(String), startTime(DateTime), endTime(DateTime). I use joda time. This is what I have done:

Map<String, DateTime> durations = activities.stream().collect(Collectors.toMap(
                                  it -> it.activityLabel,
                                  it ->new DateTime(0,0,0,0,0,0)
                                 //,DateTime::plus
                                 ));

I guess I should use DateTime plus(ReadablePeriod period) or DateTime plus(ReadableDuration duration) , but I don't know how to send a parameter of type Duration or Period to the method reference.

How can I achieve this result?

EDIT: For the input:

2011-12-03 01:00:00 2011-12-03 9:00:00 Sleeping

2011-12-04 03:00:00 2011-12-04 10:30:00 Sleeping

I should have the output: Sleeping 0-0-0 15:30:00 (years,months,days,hours,minutes,seconds)


回答1:


The code (using a Period) would look like this:

 Map<String, Period> map = activities.stream()
            .collect(Collectors.toMap(Activity::activityLabel, ac -> new Period(ac.getStartTime(), ac.getEndTime()),
                    (left, right) -> left.plus(right)));

If you really want to output that Period as a String, you need PeriodFormatter.

 private static PeriodFormatter periodFormatter() {
    return new PeriodFormatterBuilder()
            .printZeroAlways()
            .minimumPrintedDigits(2)
            .appendYears().appendSeparator("-")
            .appendMonths().appendSeparator("-")
            .appendDays().appendLiteral(" ")
            .appendHours().appendSeparator(":")
            .appendMinutes().appendSeparator(":")
            .appendSeconds().toFormatter();
}

And then your code would look more like this:

 Map<String, String> map = activities.stream()
            .collect(Collectors.collectingAndThen(
                    Collectors.toMap(
                            Activity::getLabel,
                            ac -> new Period(ac.getStartTime(), ac.getEndTime()),
                            Period::plus),
                    m -> m.entrySet().stream().collect(Collectors.toMap(
                            Entry::getKey,
                            e -> e.getValue().toString(periodFormatter)))));

    System.out.println(map);  // {Sleeping=00-00-00 15:30:00



回答2:


As you have mentioned in comment that you really need is a DateTime not a Period.

Since the DateTime has no api for DateTime.plus(DateTime)/DateTime.minus(DateTime), but you can plus / minus a Period on a DateTime , then you need a DateTime to start, and the code using Collectors api is replacing toMap with groupingBy which is more efficiently and expressiveness for doing the task in your case:

DateTime start = DateTime.now();

Map<String, DateTime> result = list.stream().collect(Collectors.groupingBy(
    it -> it.activityLabel,
    Collectors.mapping(
        it -> new Period(it.startTime, it.endTime),
        // the important section is here:
        // 1. merge all of periods by using reducing
        // 2. convert a Period to a DateTime by collectingAndThen
        Collectors.collectingAndThen(
                Collectors.reducing(Period.ZERO, Period::plus),
                start::plus
        )
    )
));


来源:https://stackoverflow.com/questions/44097658/how-to-send-parameters-to-a-reference-method-in-a-stream-java-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!