Ready-made methods for common jobs
Finding the smallest value, the largest value and the total of a list are jobs that come up all the time, and you can write each as a loop. Java also has ready-made ways to do them:
List<Integer> prices = new ArrayList<>(List.of(4, 9, 2, 7));
System.out.println(Collections.min(prices));
System.out.println(Collections.max(prices));
int total = prices.stream().mapToInt(x -> x).sum();
System.out.println(total);
The three lines print 2, 9 and 22.
Collections.min(list)returns the smallest value of the list.Collections.max(list)returns the largest value.list.stream().mapToInt(x -> x).sum()adds all the values up.
Why the sum needs mapToInt
A List<Integer> holds Integer objects, and a plain stream of them has no sum(). The call mapToInt(x -> x) turns each Integer into a plain int and gives a stream of numbers that can be added.
Math.max(a, b) compares two values, such as Math.max(3, 8), which gives 8. Collections.max looks at a whole list.
Gotchas
- Lists, not arrays.
Collections.mintakes a collection such as anArrayList. Passing anint[]is a compile error:no suitable method found for min(int[]). - An empty list. An empty list has no smallest value, so
Collections.minandCollections.maxthrow aNoSuchElementException. Checklist.isEmpty()first when the list may be empty. - The sum of an empty list is 0. The stream's
sum()doesn't throw: adding up nothing gives 0.
The lesson's task
minutes holds the minutes of coding practice on each day of a week. The task stores the shortest day in shortest, the longest in longest and the total in total, using the built-ins above.
int shortest = Collections.min(minutes);looks at every value in one call.int longest = Collections.max(minutes);does the same for the largest value.int total = minutes.stream().mapToInt(x -> x).sum();makes a stream, turns each value into anintand adds them.
The assignment to an int variable works because Java converts the Integer that Collections.min returns into an int automatically.
The solution in Java
List<Integer> minutes = new ArrayList<>(List.of(25, 40, 15, 60, 30, 45, 20));
int shortest = Collections.min(minutes);
int longest = Collections.max(minutes);
int total = minutes.stream().mapToInt(x -> x).sum();
System.out.println("shortest = " + shortest);
System.out.println("longest = " + longest);
System.out.println("total = " + total);
The output is:
shortest = 15
longest = 60
total = 235
Key takeaways
Collections.minandCollections.maxtake a list and return its extremes.- For the sum, use
mapToInt(x -> x).sum()on the list's stream. - Guard against an empty list before calling min or max.
Loop or built-in?
A loop that tracks the smallest value is fine for learning, but the built-ins say what they do in a single line and are harder to get wrong. They cannot start from a wrong value, for example, and they cannot forget a number. Use a loop when the rule is not a plain min, max or sum, for example when you need the position of the smallest value too.
Each of the three scans the list once, so they take time in proportion to the list length. Running all three, as the task does, is three passes, which is fine for a list of seven days or seven thousand.
Both Collections.min and Collections.max compare the items by their natural order. For numbers that is smaller to larger, and for strings it is alphabetical.
The names in the task say what the numbers mean. Calling the results shortest, longest and total makes the printed lines read like sentences. A name like min would work too, but it would say less about the data.
