Sometimes you gotta know if all the objects in your List share a common trait. That's when you should use allMatch() with Streams.

But the question is: how the heck do you do that?

In this guide, I'll show you how.

Better yet: I'll demonstrate how you might do this in a real-world application. None of that foo-bar stuff around here.

Ready? Let's go.

The CRM App

Let's say you're building a CRM app. It does the normal stuff that CRM apps do: tracks activities between sales reps and contacts.

Those activities get stored in a MongoDB database as documents. Each document persists info like the title of the activity as well as the type, outcome, location, start time, end time, notes, and the contact involved.

As it stands right now, if you retrieve all the documents from the activities collection, the resulting data set looks like this:

[ {
  "id" : "6016b28032d77d593dd5e19c",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Talked to him about Angular development",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Looks like he needs work for an accounting application. Could be a long-term project.",
  "location" : null,
  "startDate" : 1610474400000,
  "endDate" : 1610478000000,
  "contact" : {
    "id" : "6014199147692f2a4194ff9d",
    "firstName" : "Governor",
    "lastName" : "Rover",
    "account" : {
      "id" : "60141482b56f731fe77e902d",
      "name" : "No Moon"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "6016b316f9722c71f96cddd6",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcc0",
    "name" : "Web Form Completion",
    "icon" : "list_alt"
  },
  "title" : "Completed More Info web form on careydevelopment.us",
  "outcome" : null,
  "notes" : null,
  "location" : null,
  "startDate" : 1610305380000,
  "endDate" : 1610308980000,
  "contact" : {
    "id" : "6014199147692f2a4194ff9d",
    "firstName" : "Governor",
    "lastName" : "Rover",
    "account" : {
      "id" : "60141482b56f731fe77e902d",
      "name" : "No Moon"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601e8819b2e66d12ef1dc4ef",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Another phone call",
  "outcome" : null,
  "notes" : "Looks promising. Really.",
  "location" : null,
  "startDate" : 1612527300000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9d",
    "firstName" : "Governor",
    "lastName" : "Rover",
    "account" : {
      "id" : "60141482b56f731fe77e902d",
      "name" : "Working for Han"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601f2a162a913d1b4e94fef9",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : null,
  "notes" : null,
  "location" : "Bruno's",
  "startDate" : 1612891800000,
  "endDate" : 1612895400000,
  "contact" : {
    "id" : "6014199147692f2a4194ff95",
    "firstName" : "Lucy",
    "lastName" : "Cheng",
    "account" : {
      "id" : "60141483b56f731fe77e902e",
      "name" : "Queen Inc."
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fd4dcda249c7531fd28f0",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbf",
    "name" : "Text Message",
    "icon" : "textsms"
  },
  "title" : "Texted me about an opening",
  "outcome" : null,
  "notes" : "She said she might have an opening in the next 6 months.",
  "location" : null,
  "startDate" : 1610719200000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff95",
    "firstName" : "Lucy",
    "lastName" : "Cheng",
    "account" : {
      "id" : "60141483b56f731fe77e902e",
      "name" : "Queen Inc."
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fd63fda249c7531fd28f1",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcc0",
    "name" : "Web Form Completion",
    "icon" : "list_alt"
  },
  "title" : "Completed more info form on careydevelopment.us",
  "outcome" : null,
  "notes" : null,
  "location" : null,
  "startDate" : 1610452800000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff95",
    "firstName" : "Lucy",
    "lastName" : "Cheng",
    "account" : {
      "id" : "60141483b56f731fe77e902e",
      "name" : "Queen Inc."
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fd6b0da249c7531fd28f2",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcc1",
    "name" : "Web Page Visited",
    "icon" : "web"
  },
  "title" : "Visited page about Full Stack services",
  "outcome" : null,
  "notes" : null,
  "location" : null,
  "startDate" : 1610553600000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff95",
    "firstName" : "Lucy",
    "lastName" : "Cheng",
    "account" : {
      "id" : "60141483b56f731fe77e902e",
      "name" : "Queen Inc."
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fd76fda249c7531fd28f3",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Emailed me asking about REST development",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06c",
    "name" : "Appointment Scheduled"
  },
  "notes" : "She's looking to a legacy project into a solution with REST and MongoDB.",
  "location" : null,
  "startDate" : 1609855200000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fdafc8fc6df7eddcf3ae2",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbd",
    "name" : "Chat",
    "icon" : "chat"
  },
  "title" : "Chatted with her via Skype",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Talked about our history of delivering outstanding Java Enterprise software.",
  "location" : null,
  "startDate" : 1610367300000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fdb8c8fc6df7eddcf3ae3",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : null,
  "notes" : "Good conversation about our existing clients. She seemed very interested.",
  "location" : "That Italian Joynt",
  "startDate" : 1610558100000,
  "endDate" : 1610563500000,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fdc208fc6df7eddcf3ae4",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Email Followup from lunch",
  "outcome" : {
    "id" : "6016a407ae0e817a115fd069",
    "name" : "Did Not Respond"
  },
  "notes" : null,
  "location" : null,
  "startDate" : 1610627400000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fde938fc6df7eddcf3ae5",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Sent another email just to follow up",
  "outcome" : {
    "id" : "6016a407ae0e817a115fd069",
    "name" : "Did Not Respond"
  },
  "notes" : "This was a follow-up to the first email.",
  "location" : null,
  "startDate" : 1610713800000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fdf948fc6df7eddcf3ae6",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Good conversation about Java Enterprise",
  "outcome" : null,
  "notes" : "She said that she's working with the HR team to get everything up and running.",
  "location" : null,
  "startDate" : 1611067500000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe0718fc6df7eddcf3ae7",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : null,
  "notes" : "Good conversation about her staffing issues and requirements for her clients.",
  "location" : "Banana Joe's",
  "startDate" : 1611852300000,
  "endDate" : 1611855900000,
  "contact" : {
    "id" : "6014199147692f2a4194ff9a",
    "firstName" : "Yeezu",
    "lastName" : "Joy",
    "account" : {
      "id" : "60141483b56f731fe77e9031",
      "name" : "Empire"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe0c68fc6df7eddcf3ae8",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcc0",
    "name" : "Web Form Completion",
    "icon" : "list_alt"
  },
  "title" : "Completed More Info web form on careydevelopment.us",
  "outcome" : null,
  "notes" : null,
  "location" : null,
  "startDate" : 1610369100000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9b",
    "firstName" : "Frum",
    "lastName" : "Lezilia",
    "account" : {
      "id" : "60141483b56f731fe77e9034",
      "name" : "International Business"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe1938fc6df7eddcf3ae9",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : null,
  "notes" : "Good conversation - will follow up next week",
  "location" : "Izzy's",
  "startDate" : 1610516700000,
  "endDate" : 1610563500000,
  "contact" : {
    "id" : "6014199147692f2a4194ff9b",
    "firstName" : "Frum",
    "lastName" : "Lezilia",
    "account" : {
      "id" : "60141483b56f731fe77e9034",
      "name" : "International Business"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe1eb8fc6df7eddcf3aea",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbd",
    "name" : "Chat",
    "icon" : "chat"
  },
  "title" : "Chatted via Skype",
  "outcome" : null,
  "notes" : "Still a little reluctant - will keep trying",
  "location" : null,
  "startDate" : 1610628300000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9b",
    "firstName" : "Frum",
    "lastName" : "Lezilia",
    "account" : {
      "id" : "60141483b56f731fe77e9034",
      "name" : "International Business"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe2488fc6df7eddcf3aeb",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbd",
    "name" : "Chat",
    "icon" : "chat"
  },
  "title" : "Another Skype chat",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Seems interested in our Angular services based on the work we did for Rover. Let's hear it for good references.",
  "location" : null,
  "startDate" : 1610714700000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9b",
    "firstName" : "Frum",
    "lastName" : "Lezilia",
    "account" : {
      "id" : "60141483b56f731fe77e9034",
      "name" : "International Business"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe2b58fc6df7eddcf3aec",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Email inquiring about our Angular services",
  "outcome" : null,
  "notes" : "Wants to do know if we can do accounting apps. I gave him a list of references. Will follow up.",
  "location" : null,
  "startDate" : 1610455500000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff99",
    "firstName" : "Opus",
    "lastName" : "Mei",
    "account" : {
      "id" : "60141483b56f731fe77e9032",
      "name" : "Sandz"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe2ef8fc6df7eddcf3aed",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Further email about the work we do",
  "outcome" : {
    "id" : "6016a407ae0e817a115fd069",
    "name" : "Did Not Respond"
  },
  "notes" : "Sent the boiler plate email with some personalization.",
  "location" : null,
  "startDate" : 1610715600000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff99",
    "firstName" : "Opus",
    "lastName" : "Mei",
    "account" : {
      "id" : "60141483b56f731fe77e9032",
      "name" : "Sandz"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe3338fc6df7eddcf3aee",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Called to talk about Angular services",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Seems genuinely interested. Getting budget house in order.",
  "location" : null,
  "startDate" : 1610985600000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff99",
    "firstName" : "Opus",
    "lastName" : "Mei",
    "account" : {
      "id" : "60141483b56f731fe77e9032",
      "name" : "Sandz"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe3848fc6df7eddcf3aef",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Good conversation. Ready to pull the trigger.",
  "location" : "Izzy's",
  "startDate" : 1612281600000,
  "endDate" : 1612285200000,
  "contact" : {
    "id" : "6014199147692f2a4194ff99",
    "firstName" : "Opus",
    "lastName" : "Mei",
    "account" : {
      "id" : "60141483b56f731fe77e9032",
      "name" : "Sandz"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe3c68fc6df7eddcf3af0",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbd",
    "name" : "Chat",
    "icon" : "chat"
  },
  "title" : "Seems curious",
  "outcome" : null,
  "notes" : "Chatted via Skype. Seems interested in our products but no purchasing authority.",
  "location" : null,
  "startDate" : 1612702800000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9c",
    "firstName" : "Bert",
    "lastName" : "Simmz",
    "account" : {
      "id" : "60141483b56f731fe77e9035",
      "name" : "No Moon"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe3fc8fc6df7eddcf3af1",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Emailed me",
  "outcome" : null,
  "notes" : "Emailed me to ask more about our services. Sent the boiler plate reply and asked for info about someone with purchasing authority.",
  "location" : null,
  "startDate" : 1612270800000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff9c",
    "firstName" : "Bert",
    "lastName" : "Simmz",
    "account" : {
      "id" : "60141483b56f731fe77e9035",
      "name" : "No Moon"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe44c8fc6df7eddcf3af2",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Emailed me",
  "outcome" : null,
  "notes" : "Curious about our services. I sent a reply with references.",
  "location" : null,
  "startDate" : 1610542800000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff97",
    "firstName" : "Blinky",
    "lastName" : "Scene",
    "account" : {
      "id" : "60141483b56f731fe77e9030",
      "name" : "For Luke"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe48d8fc6df7eddcf3af3",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbd",
    "name" : "Chat",
    "icon" : "chat"
  },
  "title" : "Chatted via Skype",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06c",
    "name" : "Appointment Scheduled"
  },
  "notes" : "Asked about our experience with Java Enterprise. I talked about our top developers.",
  "location" : null,
  "startDate" : 1611234000000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff97",
    "firstName" : "Blinky",
    "lastName" : "Scene",
    "account" : {
      "id" : "60141483b56f731fe77e9030",
      "name" : "For Luke"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe4f98fc6df7eddcf3af4",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Talked more about Java Enterprise and the work we do. Gave highlights of some of the solutions we've delivered in the past.",
  "location" : "Loony's",
  "startDate" : 1611939600000,
  "endDate" : 1611943200000,
  "contact" : {
    "id" : "6014199147692f2a4194ff97",
    "firstName" : "Blinky",
    "lastName" : "Scene",
    "account" : {
      "id" : "60141483b56f731fe77e9030",
      "name" : "For Luke"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe5ee8fc6df7eddcf3af5",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Email followup",
  "outcome" : {
    "id" : "6016a407ae0e817a115fd069",
    "name" : "Did Not Respond"
  },
  "notes" : "Followup email after lunch appointment.",
  "location" : null,
  "startDate" : 1612357200000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff97",
    "firstName" : "Blinky",
    "lastName" : "Scene",
    "account" : {
      "id" : "60141483b56f731fe77e9030",
      "name" : "For Luke"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe6268fc6df7eddcf3af6",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Called me to ask about Angular services",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Good conversation. Seems genuinely interested.",
  "location" : null,
  "startDate" : 1610629200000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff96",
    "firstName" : "Mercy",
    "lastName" : "Windsor",
    "account" : {
      "id" : "60141483b56f731fe77e902f",
      "name" : "Cloud City"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe65e8fc6df7eddcf3af7",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Follow-up email",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06c",
    "name" : "Appointment Scheduled"
  },
  "notes" : "Send a follow-up email explaining more about our Angular services.",
  "location" : null,
  "startDate" : 1610975700000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff96",
    "firstName" : "Mercy",
    "lastName" : "Windsor",
    "account" : {
      "id" : "60141483b56f731fe77e902f",
      "name" : "Cloud City"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe6aa8fc6df7eddcf3af8",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : null,
  "location" : "Izzy's",
  "startDate" : 1611854100000,
  "endDate" : 1611857700000,
  "contact" : {
    "id" : "6014199147692f2a4194ff96",
    "firstName" : "Mercy",
    "lastName" : "Windsor",
    "account" : {
      "id" : "60141483b56f731fe77e902f",
      "name" : "Cloud City"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe6f38fc6df7eddcf3af9",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Went with another company",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06b",
    "name" : "Not Interested"
  },
  "notes" : "Decided to go with another company for services. Will follow up in several months.",
  "location" : null,
  "startDate" : 1612358100000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff96",
    "firstName" : "Mercy",
    "lastName" : "Windsor",
    "account" : {
      "id" : "60141483b56f731fe77e902f",
      "name" : "Cloud City"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
} ]

As you can see, we're not messing around here. You're going to be working with real-world data.

On the Java side, the Activity class with its related classes mimic the data set that you see above. You can see examples of some of those classes over on GitHub.

So you can just do a findAll() on that collection above and get a List of Java objects that represent that JSON output. Then, you can use a Java Stream to filter, find, and map as you see fit.

That's what you'll do in this guide.

And, yes, you could do that kind of stuff with MongoDB aggregations. But you're not here to learn about aggregations are you?

Starting the Year Off Right

Your CRM application just launched at the beginning of 2021. Now it's time to do a sanity check on the data.

In this case, you want to make sure that all activity start dates are on or after January 1, 2021. To do that, you'll enlist the aid of a Java Stream.

The first thing you need to do is take a look at the dataset above. You'll see that the date is stored as a Long

Why? I always find it easier to store dates as a number. Then, the UI can determine how it wants to format the data for display to the end user.

Anyhoo, that means you got to translate January 1, 2021 at midnight into a number.

By the way, that Long number in this case represents the number of milliseconds since 1970 began. Some folks call that the current epoch but that sounds like we're living in Jurassic Park.

There are a few ways you can skin that cat of getting the numerical value for the moment 2021 began. Here's one of them:

        Long beginningOfYear = LocalDate
                                .parse("2021-01-01")
                                .atStartOfDay()
                                .atZone(ZoneId.systemDefault())
                                .toInstant()
                                .toEpochMilli();

Yeah that kind of sucks, doesn't it? The folks at Oracle still need to find a better way to handle dates and times.

But let's go with that because it works.

Now here's what you need to do next: iterate through each of the activities and compare the start date to the beginningOfYear value you just created above. All the start dates should be equal to or greater than that number.

Stream of Consciousness

Of course, you could do the forEach() thing right off the List to make the comparison. But again, that's not why you're here, is it?

Also, you can accomplish the same thing with a Stream but with less code. And everybody loves less code.

So let's do this:

        List<Activity> activities = activityRepo.findAll();
        
        Long beginningOfYear = LocalDate
                                .parse("2021-01-01")
                                .atStartOfDay()
                                .atZone(ZoneId.systemDefault())
                                .toInstant()
                                .toEpochMilli();

        boolean correctDates = activities
                                .stream()
                                .allMatch(activity -> activity.getStartDate() != null && activity.getStartDate() >= beginningOfYear);
        
        System.err.println(correctDates);

The first line gets all the activities from the collection.

The second line sets the top of the year 2021 as a number. You saw that earlier.

The third line handles the Stream work. That's where the magic happens.

That line of code converts the List object into a Stream. Then it can perform Stream-related activities on the collection.

The first (and only) Stream-related activity it performs is allMatch(). But what does that do?

It returns a boolean. That's it. That's what it does.

That boolean will be true if all objects in the collection match the Predicate.

Yeah. The Predicate.

But what is a Predicate? In the world of computer science, it's a function that returns a boolean. 

In Java specifically, you can check out the API docs on the Predicate class to learn more about it. Since it's a functional interface, you can implement a Predicate with a lambda expression.

Now you might be wondering about the phrase "functional interface." What is that?

In Java, it's an interface with a single abstract method. Then, you can assign a lambda expression to that Predicate and it will execute that code as an implementation of that method.

In the case of Predicate, that single abstract method is test(). You see the implementation of that method in the code above, although it's far from obvious.

Take a look at the boolean test inside of allMatch(). It's two-fold: 

  • A check to make sure that activity start date isn't null
  • A check to make sure the activity start date is equal to or greater than the beginning of the year 2021

Keep in mind: it runs that check for each and every Activity object in the collection. And that boolean must evaluate to true for all objects in order for allMatch() to return true.

That's how the method got its name, after all.

So now: given the dataset above if you run that code, you'll get the following output in bright red letters:

true

And that's what you'd expect because if you look at the dataset you'll find that all dates are non-null and they're all later than the beginning of the year 2021.

Another Sanity Check

Now let's say you want to do another sanity check on the data that's out there as your CRM app goes into production. Maybe you want to make sure that all activities are associated with contacts.

How would you do that?

Like this:

        List<Activity> activities = activityRepo.findAll();
        
        boolean contactsExist = activities
                                .stream()
                                .allMatch(activity -> activity.getContact() != null);
        
        System.err.println(contactsExist);

Once again, run that code and you'll find that it spits out true.

And, once again, that's what you'd expect because all activities in the dataset above are associated with a contact.

Wrapping It Up

And there you have it: a crash-course on the allMatch() method with a Java Stream.

Now it's up to you to make it your own. Think about how you'd use allMatch() to satisfy the requirements of applications you're working on right now.

And then implement your solution.

Have fun!

Image by congerdesign from Pixabay