IgnitedMind
IgnitedMind

Reputation: 35

Java8 filter arraylist with custom object on field date

I have to filter List<Card> on the field, issueDate(type String), where cards to be shown till last 7 years date.

The solution that I've tried is to parse issueDate field from String to Date and then apply date.after(startDate) and date.before(endDate) as below:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
cardList.stream()
        .map(s->s.getIssueDate())
        .filter(dt -> sdf.parse(dt).after(sdf.parse("2020-06-08")) && 
                      sdf.parse(dt).before(sdf.parse("2020-08-12")))
        .collect(Collectors.toList());  

Even can't apply for loop as there can be hundreds of cards issued, and it impacts performance by iterating on each card issue date(string to date and check year)

Can anyone suggest a good solution to this problem?

Upvotes: 0

Views: 1790

Answers (2)

ETO
ETO

Reputation: 7279

Not sure you need to parse the dates here. All of your dates are String and have the same yyyy-MM-dd format.

In this particular case you could simply compare the strings lexicographically:

String from = "2020-06-08";
String to = "2020-08-12";

List<Card> filteredCardList = 
    cardList.stream()
            .filter(card -> card.getIssueDate().compareTo(from) > 0)
            .filter(card -> card.getIssueDate().compareTo(to) < 0)
            .collect(toList());

or you do the same with plain old loop:

List<Card> filteredCardList = new ArrayList<>();
for(Card card : cardList) {
    String date = card.getIssueDate();
    if(date.compareTo(from) > 0 && date.compareTo(to) < 0) {
        filteredCardList.add(card);
    }
}

Upvotes: 0

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79425

There are many problems with your code:

  1. The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API* .
  2. You should declare issueDate as LocalDate (or Date if you still want to stick to the legacy API) instead of String. However, for any reason, if you still want to keep it as String, you can change your code to parse it to a date-type object only once during Stream processing (currently, you are doing it twice).
  3. You are parsing 2020-06-08 and 2020-08-12 inside Stream processing whereas they are static values and therefore they should be parsed outside the Stream processing. In fact, if these static dates are not as String, you can create date-type objects directly e.g. LocalDate start = LocalDate.of(2020, 6, 8).

These suggestions have been incorporated in the following code:

LocalDate start = LocalDate.parse("2020-06-08");
LocalDate end = LocalDate.parse("2020-08-12");

List<LocalDate> dates = 
        cardList.stream()
                .map(card -> LocalDate.parse(card.getIssueDate()))
                .filter(ld -> ld.isAfter(start) && ld.isBefore(end))
                .collect(Collectors.toList());

If you want to collect the Stream into a list of cards, you can do it as follows:

List<Card> cards = 
        cardList.stream()
                .filter(card -> {
                    LocalDate ld = LocalDate.parse(card.getIssueDate());                            
                    return ld.isAfter(start) && ld.isBefore(end);
                })
                .collect(Collectors.toList());

* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project. Learn more about the modern date-time API from Trail: Date Time.

Upvotes: 5

Related Questions