【问题标题】:java 8 stream for sorting a list of objects based on particular fieldjava 8流,用于根据特定字段对对象列表进行排序
【发布时间】:2018-10-03 04:18:50
【问题描述】:

我有一个场景可以根据时间戳对对象进行排序。类如下:

class Employee 
{
    private String name;
    private List<Address> addresses;

    //...
    //Getters and setters for all fields
}

public class Address
{
    private String city;
    private Timestamp startDate;
    private Timestamp endDate;
    private String typeOfResidence;

    //...
    //Getters and setters for all the fields
}

对于员工,有两种可能性 1.它将有一个地址列表。 2.地址列表可以为空

地址类有一个字段typeOfResidence,它的值可以是Residence、Office、ForeignHome。

每个Employee 可以有地址列表,一个地址是住宅,另一个是办公室等等。可以有多个住宅地址,但只有一个办公地址。

我想根据 typeOfResidence=Office 的地址的 startDate 对员工列表进行排序。

我写了以下代码:

private void sortEmployeeListBasedOnStartDate(List<Employee> employeeList)
{
    Comparator<Address> byTimeStamp = Comparator.comparing(
        Address::getStarteDate,
        (ts1, ts2) -> ts1.toGregorianCalendar().compareTo(ts2.toGregorianCalendar())
    );

    employeeList.stream()
        .map(x -> getLatestAddressByType(x, "Office"))
        .filter(y -> y!=null)
        .sorted(byTimeStamp.reversed())
        .collect(Collectors.toList());
}

public Address getLatestAddressByType(Employee employee, String type)
{
    if(role != null && brokerageManagedProposalType != null)
    {
         return getUserAddress(employee).stream()
            .filter(address-> address.getTypeOfResidence().equals(type))
            .findFirst()
            .orElse(null);
    }
    return null;
}

public List<Address> getUserAddress(Employee employee)
{
    if (!NullChecker.isNull(employee) && !NullChecker.isNull(employee.getAddress()))
    {
        return employee.getAddress();
    }
    return Collections.emptyList();
}

不知何故,这似乎不起作用。员工没有排序。请帮我让它工作。

【问题讨论】:

    标签: java sorting java-stream comparator


    【解决方案1】:

    如果您想要就地排序,可以使用Collections.sort 代替流。

    Collections.sort(employeeList, 
        (e1,e2) -> byTimeStamp.compare(
            getLatestAddressByType(e2, "Office"),
            getLatestAddressByType(e1, "Office") );
    

    同样,null-filtering 问题可以就地解决,如下所示:

    employeeList.removeIf(e -> getLatestAddressByType(e, "Office") == null);
    

    (顺便说一句,getLatestAddressByType 应该是Employee 的实例方法)

    【讨论】:

    • 有没有什么方法可以将空值检查和排序合并在一个语句中?
    • @azaveri7 是的,您可以将第二条语句插入“排序”的第一个参数,但为了便于阅读,我建议不要这样做。
    • 非常感谢马可。
    【解决方案2】:

    您的sortEmployeeListBasedOnStartDate 方法不会改变输入List&lt;Employee&gt;。它创建了一个新的排序List&lt;Address&gt;,你什么也不做。

    如果您想要一个已排序的List&lt;Employee&gt;,则不应将Employees 映射到Addresses。您应该生成一个已排序的 List&lt;Employee&gt; 并返回该 List

    应该这样做:

    private List<Employee> sortEmployeeListBasedOnStartDate(List<Employee> employeeList)
    {
        Comparator<Address> byTimeStamp = Comparator.comparing(
            Address::getStarteDate,
            (ts1, ts2) -> ts1.toGregorianCalendar().compareTo(ts2.toGregorianCalendar())
        );
    
        return employeeList
            .stream()
            .sorted((e1,e2)->byTimeStamp.compare(getLatestAddressByType(e2, "Office"),getLatestAddressByType(e1, "Office")))
            .collect(Collectors.toList());
    }
    

    您可能需要为getLatestAddressByType() 返回null 的情况添加一些处理:

        return employeeList
            .stream()
            .filter(e->getLatestAddressByType(e, "Office") != null)
            .sorted((e1,e2)->byTimeStamp.compare(getLatestAddressByType(e2, "Office"),getLatestAddressByType(e1, "Office")))
            .collect(Collectors.toList());
    

    【讨论】:

      【解决方案3】:

      你的问题在这里:

      employeeList.stream()
          .map(x -> getLatestAddressByType(x, "Office"))
          .filter(y -> y!=null)
          .sorted(byTimeStamp.reversed())
          .collect(Collectors.toList());
      

      这不是就地排序。 employeeList 中的值保持完全相同。 collect 正在创建一个新的 List 实例,该实例从未分配给变量或返回 - 该实例只是简单地创建,然后立即无法进行垃圾回收。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-03
        相关资源
        最近更新 更多