How to send parameters to a reference method in a

2019-05-25 07:02发布

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)

2条回答
淡お忘
2楼-- · 2019-05-25 07:11

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
        )
    )
));
查看更多
Animai°情兽
3楼-- · 2019-05-25 07:17

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
查看更多
登录 后发表回答