使用 Java 8 lambda 表达式,按内部列表的属性过滤对象列表

Exc*_*ser 1 java lambda datetime filtering max

我是Java lambda 表达式的新手,一直在努力解决以下问题:

我正在尝试将以下 Activity 对象列表过滤为具有最近开始时间的单个 Activity:

{
     Name: "activity1"
     Id: "abc-123"
     Fields: [
          { key: "startTime", value: "2018-08-24T12:00:01" },
          { key: "foo", value: "bar" },
          { key: "baz", value: "zoop" }
     ]
},
{
     Name: "activity2"
     Id: "def-456"
     Fields: [
          { key: "bat", value: "zap" },
          { key: "startTime", value: "2018-08-23T12:00:01" },
          { key: "cat", value: "dog" }
     ]
},
{
     Name: "activity3"
     Id: "ghi-789"
     Fields: [
          { key: "flim", value: "flam" },
          { key: "boop", value: "bop" },
          { key: "startTime", value: "2018-08-22T12:00:01" }
     ]
}
Run Code Online (Sandbox Code Playgroud)

基本上,每个对象都有一个内部字段列表,这些字段不按特定顺序出现,我想根据具有最大日期的“startTime”字段将父集合过滤为一项。

对于示例数据,目标是仅返回名称为“activity1”的对象。请注意,Field 对象在我的数据中没有特定的顺序出现。此外,如果一个活动的开始时间与另一个活动的开始时间相匹配,则代码应采用集合中第一个出现的项目。

假设活动和字段位于列表中,并且我的 Activity 类上有 getter/setter,这就是我开始的内容,但我知道这是不正确的:

activities().stream().filter(activity ->  
    activity.getFields().stream()
            .filter(field -> field.getKey().equals("startTime"))
            .max((field1, field2) -> {
                Date date1 = Date.from(Instant.parse(field1.getValue()));
                Date date2 = Date.from(Instant.parse(field2.getValue()));
                return date1.compareTo(date2);
            }).isPresent()
).findAny().get();
Run Code Online (Sandbox Code Playgroud)

任何帮助或我应该如何解决这个问题的例子将非常感激。谢谢!


Edit-1:我正在使用的 实际类ActivityField类是从第三方库中检索的,而不是我自己设计的。以下是它们的外观:

public class Activity {
     private String id;
     private String name;
     private List<Field> fields;

     public String getId() {
         return id;
     }

     public void setId(String id) {
         this.id = id;
     }

     public String getName() {
         return name;
     }

     public void setName(String name) {
         this.name = name;
     }

     public List<Field> getFields() {
         return fields;
     }

     public void setFields(List<Field> fields) {
         this.fields = fields;
     }
 }

public class Field {
     private String key;
     private String value;

     public String getKey() {
         return key;
     }

     public void setKey(String key) {
         this.key = key;
     }

     public String getValue() {
         return value;
     }

     public void setValue(String value) {
         this.value = value;
     }
 }
Run Code Online (Sandbox Code Playgroud)

jac*_*obm 5

您可能想要定义一个提取日期的函数,然后使用Collectors.maxBy. 例如:

// Somewhere in your class:
Instant startDate(Activity activity) {
  return activity.getFields()
    .stream()
    .filter(field -> field.getKey().equals("startTime"))
    .map(field -> Instant.parse(field.getValue()))
    .findAny()
    .get();
}

// .. and then to use it:
Optional<Activity> maxStartDateActivity = activities()
    .stream()
    .max(Comparator.comparing(MyClass::startDate));
Run Code Online (Sandbox Code Playgroud)

旁注:您可能不应该按原样表示数据。为您的值定义一个接口是值得的Activity,它可以让您执行一些操作,例如将解析的开始时间作为单个调用获取,然后可以在流管道中使用。这样做将有助于将活动的表示方式与您尝试使用它们执行的操作分离开来,这将使您的整个程序更易于阅读,更容易添加更多功能,并且在将来更容易更改。