Of course, it always depends on the circumstances. Take the original example:
List<Integer> list = Arrays.asList(1,4,3,9,7,4,8); list.stream().max(Comparator.naturalOrder()).ifPresent(System.out::println);
If you want to do the same thing effectively, you should use
IntStream.of(1,4,3,9,7,4,8).max().ifPresent(System.out::println);
which does not provide for any automatic boxing. But if your assumption is to have a List<Integer> in advance, this might not be an option, so if you're just interested in the value of max , Collections.max might be an easier choice.
But that would lead to the question of why you have a List<Integer> in advance. Maybe this is the result of the old code (or new code written using the old thinking), which had no choice but to use boxing and Collection , since there was no alternative in the past?
So maybe you should think about the source that produces the collection before worrying about how to consume it (or well, think about all at the same time).
If all you have is Collection , and all you need is a single terminal operation for which there is a simple implementation based on Collection , you can use it directly without worrying about the Stream API. API designers recognized this idea by adding methods such as forEach(…) to the Collection API, instead of insisting on using all stream().forEach(…) . And Collection.forEach(…) not a simple short hand for Collection.stream().forEach(…) , in fact, it is already defined on the more abstract Iterable interface, which does not even have a stream() method.
Btw., You should understand the difference between Collections.binarySearch and Stream.filter/findAny . The first requires the collection to be sorted, and if this condition is met, it might be a better choice. But if the collection is not sorted, a simple linear search is more efficient than sorting for only one use of binary search, not to mention that binary search works with List only when filter / findAny works with any stream that supports each type of source collection .