Code Explanation:
The following Java code demonstrates the usage of Java Streams to perform various operations on a list of Course
objects. It covers common stream operations such as filtering, sorting, matching, grouping, and aggregation. Below is a detailed explanation of the code:
1. List of Course Objects
The code starts by creating a list of Course
objects, each having attributes like name
, category
, reviewScore
, and noOfStudents
:
java
List<Course> courses = List.of(
new Course("Spring", "Framework", 98, 20000),
new Course("Spring Boot", "Framework", 95, 18000),
new Course("API", "Microservices", 97, 22000),
new Course("Microservices", "Microservices", 96, 25000),
new Course("FullStack", "FullStack", 91, 14000),
new Course("AWS", "Cloud", 92, 21000),
new Course("Azure", "Cloud", 99, 21000),
new Course("Docker", "Cloud", 92, 20000),
new Course("Kubernetes", "Cloud", 91, 20000)
);
2. Predicate for Filtering
Predicates are functional interfaces that represent conditions. The following predicate checks if a course's review score is greater than 90:
java
Predicate<Course> reviewScoreGreaterThan90 = course -> course.getReviewScore() > 90;
This predicate is used with allMatch
, noneMatch
, and anyMatch
methods to test multiple conditions on the stream of courses:
allMatch
checks if all courses satisfy the condition (reviewScore > 90
):
java
System.out.println(courses.stream().allMatch(reviewScoreGreaterThan90));
noneMatch
checks if none of the courses satisfy the condition (reviewScore < 90
):
java
Predicate<Course> reviewScoreLessThan90 = getPredicateForReviewScoreLessThan90();
System.out.println(courses.stream().noneMatch(reviewScoreLessThan90));
anyMatch
checks if any course satisfies the condition (reviewScore > 97
):
java
Predicate<Course> reviewScoreGreaterThan97 = course -> course.getReviewScore() > 97;
System.out.println(courses.stream().anyMatch(reviewScoreGreaterThan97));
3. Sorting Courses
Sorting can be done using Comparator
. The following examples demonstrate sorting by the number of students:
- Sorting by number of students in increasing order:
java
Comparator<Course> comparingNumberOfStudentsIncreasing = Comparator.comparing(Course::getNoOfStudents);
System.out.println(courses.stream().sorted(comparingNumberOfStudentsIncreasing).collect(Collectors.toList()));
- Sorting by number of students in decreasing order:
java
Comparator<Course> comparingNumberOfStudentsDecreasing = Comparator.comparing(Course::getNoOfStudents).reversed();
System.out.println(courses.stream().sorted(comparingNumberOfStudentsDecreasing).collect(Collectors.toList()));
- Sorting by number of students and review scores in decreasing order (using
thenComparing
):
java
Comparator<Course> comparingNumberOfStudentsAndReviewScoresDecreasing =
Comparator.comparing(Course::getNoOfStudents)
.thenComparing(Course::getReviewScore)
.reversed();
System.out.println(courses.stream().sorted(comparingNumberOfStudentsAndReviewScoresDecreasing).collect(Collectors.toList()));
4. Skipping and Limiting Results
Stream operations such as skip
and limit
allow you to control the number of elements processed:
- Skipping the first three courses sorted by name:
java
System.out.println(courses.stream().sorted(Comparator.comparing(Course::getName)).skip(3).collect(Collectors.toList()));
- Limiting the results after skipping:
java
System.out.println(courses.stream().sorted(Comparator.comparing(Course::getName)).skip(3).limit(2).collect(Collectors.toList()));
5. Taking and Dropping Elements Based on a Condition
Stream methods like takeWhile
and dropWhile
allow conditional filtering:
takeWhile
takes elements while their names are less than or equal to 9 characters:
java
System.out.println(courses.stream().sorted(Comparator.comparing(Course::getName)).takeWhile(course -> course.getName().length() <= 9).collect(Collectors.toList()));
dropWhile
drops elements while their names are less than or equal to 9 characters:
java
System.out.println(courses.stream().sorted(Comparator.comparing(Course::getName)).dropWhile(course -> course.getName().length() <= 9).collect(Collectors.toList()));
6. Finding Min, Max, and First Elements
You can find the minimum or maximum elements based on a comparator, or retrieve the first element:
- Finding the maximum course by name in reversed order:
java
System.out.println(courses.stream().max(Comparator.comparing(Course::getName).reversed()).orElse(new Course("AWS", "Cloud", 92, 21000)));
- Finding the minimum course by name in reversed order:
java
System.out.println(courses.stream().min(Comparator.comparing(Course::getName).reversed()).orElse(new Course("AWS", "Cloud", 92, 21000)));
- Finding the first course with a name length greater than 9:
java
System.out.println(courses.stream().filter(c -> c.getName().length() > 9).findFirst().orElse(new Course("AWS", "Cloud", 92, 21000)));
7. Aggregating Results
Java streams offer various aggregation methods such as sum
, average
, and count
:
- Sum of students for courses with review scores greater than 95:
java
System.out.println(courses.stream().filter(c -> c.getReviewScore() > 95).mapToInt(Course::getNoOfStudents).sum());
- Average number of students for courses with review scores greater than 95:
java
System.out.println(courses.stream().filter(c -> c.getReviewScore() > 95).mapToInt(Course::getNoOfStudents).average());
- Counting the number of courses with review scores greater than 95:
java
System.out.println(courses.stream().filter(c -> c.getReviewScore() > 95).mapToInt(Course::getNoOfStudents).count());
8. Grouping Courses
You can group courses by certain criteria such as category:
- Group courses by category:
java
System.out.println(courses.stream().collect(Collectors.groupingBy(Course::getCategory)));
- Group courses by category and count the number of courses in each category:
java
System.out.println(courses.stream().collect(Collectors.groupingBy(Course::getCategory, Collectors.counting())));
9. Joining Course Names
The joining
method allows you to concatenate course names into a single string:
- Joining course names with commas:
java
System.out.println(courses.stream().map(Course::getName).collect(Collectors.joining(",")));
10. Advanced Operations: FlatMap
The code demonstrates more complex operations using flatMap
, such as splitting course names into individual characters and collecting distinct characters:
- Splitting names into characters and collecting distinct ones:
java
System.out.println(courses.stream().map(s -> s.getName().split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList()));
Helper Method
The method getPredicateForReviewScoreLessThan90
returns a predicate that checks if a course’s review score is below 90:
java
public static Predicate<Course> getPredicateForReviewScoreLessThan90() {
return course -> course.getReviewScore() < 90;
}
Summary:
The code showcases how Java Streams can be leveraged for:
- Filtering, matching, and sorting collections
- Aggregating data
- Grouping elements based on specific attributes
- Performing advanced operations like
flatMap
and joining
.
By using lambdas and Stream API methods, the code exemplifies an expressive, concise, and efficient approach to handling collections in Java.