Сортировка значений даты в Java - PullRequest
0 голосов
/ 17 октября 2018

У меня есть List<object>, где у меня есть свойство manufacturedDate, где я должен сделать sortingList<Object> есть некоторые значения как null для manufacturedDate.Сортировка не происходит должным образом.Я не уверен, что это из-за значений null.list не возвращает значения в порядке asc или desc manufacturedDate.

Ниже приведен мой код:

    if(sortType.equalsIgnoreCase("manufacturedDate"))
    {
        DateFormat sdf1 = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
        if(manufacturedDateSortAsc.equalsIgnoreCase("Desc"))
        {
            manufacturedDateSortAsc = "Asc";
            Collections.sort(carList, new Comparator<CarDataTransferObject>() 
            {
                public int compare(CarDataTransferObject object1, CarDataTransferObject object2) 
                {
                    int returnVal = 0;
                    try 
                    {
                        returnVal = sdf1.parse(object1.getManufacturedDate()).compareTo(sdf1.parse(object2.getManufacturedDate()));
                    } 
                    catch (Exception e) 
                    {
                        log.error("Error inside sortList method"+e);
                    }
                    return returnVal;                       
                }
            });
        }
        else
        {
            usReleaseDateSortAsc = "Desc";
            Collections.sort(carList, new Comparator<CarDataTransferObject>() 
            {
                public int compare(CarDataTransferObject object1, CarDataTransferObject object2) 
                {
                    int returnVal = 0;
                    try 
                    {
                        returnVal = sdf1.parse(object2.getManufacturedDate()).compareTo(sdf1.parse(object1.getManufacturedDate()));                             
                    } 
                    catch (Exception e) 
                    {
                        log.error("Error inside sortList method"+e);
                    }
                    return returnVal;                       
                }
            });
        }
    }

Ответы [ 5 ]

0 голосов
/ 18 октября 2018

Я использую этот класс для демонстрации:

public class CarDataTransferObject {

    private static final DateTimeFormatter DATE_FORMATTER
            = DateTimeFormatter.ofPattern("dd-MMM-yyyy", Locale.ENGLISH);

    LocalDate manufacturedDate;

    public CarDataTransferObject(String manufacturedDateString) {
        if (manufacturedDateString == null) {
            manufacturedDate = null;
        } else {
            manufacturedDate = LocalDate.parse(manufacturedDateString, DATE_FORMATTER);
        }
    }

    // getter, toString, …

}

Для сортировки по возрастанию:

    List<CarDataTransferObject> carList = Arrays.asList(
            new CarDataTransferObject("23-Sep-2018"),
            new CarDataTransferObject(null),
            new CarDataTransferObject("04-Jul-2018"),
            new CarDataTransferObject("11-Aug-2018"),
            new CarDataTransferObject(null),
            new CarDataTransferObject("30-May-2018"));
    carList.sort(Comparator.comparing(
            CarDataTransferObject::getManufacturedDate, 
            Comparator.nullsLast(Comparator.naturalOrder())));
    carList.forEach(System.out::println);

Вывод:

Car manufactured 30-May-2018
Car manufactured 04-Jul-2018
Car manufactured 11-Aug-2018
Car manufactured 23-Sep-2018
Car (no manufactured date)
Car (no manufactured date)

Для сортировки по убыванию:

    carList.sort(Comparator.comparing(
            CarDataTransferObject::getManufacturedDate, 
            Comparator.nullsFirst(Comparator.reverseOrder())));

Вывод:

Car (no manufactured date)
Car (no manufactured date)
Car manufactured 23-Sep-2018
Car manufactured 11-Aug-2018
Car manufactured 04-Jul-2018
Car manufactured 30-May-2018

java.time и другие советы

Используйте LocalDate из java.time, современного Java-API даты и времени, для васдата изготовления.Не используйте строки.LocalDate - это дата без времени суток, так что вам нужно здесь.Форматируйте дату только в строку для представления пользователю или для сериализации.java.time встроен в Java из Java 8 (и также перенесен в Java 6 и 7).

Статические методы в интерфейсе Comparator также добавлены в Java 8 - comparing, nullsFirst и многое другое - сделать построение довольно сложных компараторов не только более простым и кратким, но и менее подверженным ошибкам.

Что пошло не так в вашем коде?

Вам необходимо явно обрабатывать нули,Метод sort может выбирать любые сравнения, которые ему нравятся (на практике он является детерминистическим, который он использует, но не рассчитывает на то, что сможет его просмотреть).Таким образом, если ваш список содержит объект с null датой, он может сравнивать любые два (или более) других объекта с объектом с нулевым значением.Каждое сравнение дает 0, поэтому сортировка теперь «знает» (неправильно), что все эти объекты принадлежат одному месту в сортировке.Сортировка стабильна, это означает, что все эти объекты выходят в том же порядке, в каком они были в списке перед сортировкой.

Вместо этого сообщите методу сортировки, хотите ли вы нулевые значения первым или последним, и вы получите то, чтоВы просите.

Ссылка

Учебное пособие по Oracle: Дата и время , объясняющее, как использовать java.time.

0 голосов
/ 17 октября 2018

Поскольку у вас есть тег java 8, вы можете отсортировать его с помощью потока:

System.out.println(list.stream()
            .sorted((obj1,obj2) -> {
                if(obj1.getManufacturedDate() != null && obj2 != null){
                    DateFormat sdf1 = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
                    try {
                        Date date1 = sdf1.parse(obj1.getManufacturedDate());
                        Date date2 = sdf1.parse(obj2.getManufacturedDate());

                        return date1.compareTo(date2);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                return 0;
            })
            .collect(Collectors.toList())
    );

Поскольку у вас есть дата, которая является строкой, нам нужно выполнить это форматирование.

Для тестирования я использовал такую ​​структуру, как этот класс:

private class MyObject {
    String manufacturedDate;

    public MyObject(String date){
        this.manufacturedDate = date;
    }
    public String getManufacturedDate(){
        return manufacturedDate;
    }

    @Override
    public String toString() {
        if(manufacturedDate != null) {
            return this.manufacturedDate;
        }else {
            return "empty";
        }
    }
}

Итак, с примерами данных вроде этого:

    List<MyObject> list = new ArrayList<>();
    list.add(new MyObject("01-JAN-2018"));
    list.add(new MyObject("01-FEB-2015"));
    list.add(new MyObject("01-MAR-2012"));
    list.add(new MyObject("01-JAN-2019"));
    list.add(new MyObject(null));

В результате вы получите:

[01 марта 2012 года, 01 февраля 2015 года, 01 января 2018 года, 01 января 2019 года, пусто]

0 голосов
/ 17 октября 2018

Попробуйте это:

 returnVal = sdf1.parse(object1.getManufacturedDate()).getTime() - sdf1.parse(object2.getManufacturedDate()).getTime();
0 голосов
/ 17 октября 2018

вместо date.before(otherDate) и date.after(otherDate).Это проще и вернет прямо логическое значение.

0 голосов
/ 17 октября 2018

Я почти уверен, что это проблема из-за значений null.

Взгляните на ваш compare() метод:

int returnVal = 0;
try {
 returnVal = sdf1.parse(object2.getManufacturedDate()).compareTo(sdf1.parse(object1.getManufacturedDate()));                             
} catch (Exception e) {
  log.error("Error inside sortList method"+e);
}
return returnVal;      

Что произойдет, если одиниз двух это null?Вы получите исключение и вернете 0.

Однако null следует всегда считать большим или меньшим, чем любое ненулевое значение.Требование для Comparator состоит в том, что результаты должны быть переходными, то есть если a < b и b < c, то a < c.Теперь, если один из них был null (скажем, c), тогда ваш код нарушил бы это, то есть это могло бы привести к a < b, b = c и a = c, что явно нарушает контракт.

Таким образом, вам нужно проверить на нули отдельно:

if(date1 == null ) {
  if (date2 == null) {
    return 0;
  } else {
    return /*either -1 or 1 depending on where nulls should end up*/
  }
} else {
  if (date2 == null) {
    return /*either 1 or -1 depending on where nulls should end up*/
  } else {
    return date1.compareTo(date2); //this assumes successful parsing, I'll leave those details for you
  }
}
...