Ответ, как всегда, зависит. Это зависит от того, насколько большой будет возвращаемая коллекция. Это зависит от того, меняется ли результат со временем, и насколько важна согласованность возвращаемого результата. И это очень сильно зависит от того, как пользователь может использовать ответ.
Во-первых, обратите внимание, что вы всегда можете получить Collection из Stream и наоборот:
// If API returns Collection, convert with stream()
getFoo().stream()...
// If API returns Stream, use collect()
Collection<T> c = getFooStream().collect(toList());
Итак, вопрос в том, что более полезно для ваших абонентов.
Если ваш результат может быть бесконечным, есть только один выбор: Stream.
Если ваш результат может быть очень большим, вы, вероятно, предпочтете Stream, поскольку материализация всего сразу может не иметь смысла, и это может создать значительное давление на кучу.
Если все, что будет делать вызывающий объект, — это перебирать его (поиск, фильтрация, агрегирование), вам следует предпочесть Stream, так как Stream уже имеет все это и нет необходимости материализовать коллекцию (особенно если пользователь может не обрабатывать весь результат.) Это очень распространенный случай.
Даже если вы знаете, что пользователь будет повторять его несколько раз или каким-либо иным образом сохранит его, вы все равно можете вместо этого вернуть Stream по той простой причине, что любое Collection, которое вы решите вставить (например, ArrayList), может не быть форма, которую они хотят, и тогда вызывающая сторона все равно должна скопировать ее. Если вы возвращаете Stream, они могут сделать collect(toCollection(factory)) и получить именно то, что им нужно.
Вышеупомянутые случаи предпочтения Stream в основном связаны с тем, что Stream более гибок; вы можете позднее привязать его к тому, как вы его используете, не неся затрат и ограничений, связанных с материализацией его в Collection.
Единственный случай, когда вы должны вернуть Collection, — это когда существуют строгие требования согласованности, и вы должны создать непротиворечивый снимок движущейся цели. Затем вам нужно будет поместить элементы в коллекцию, которая не изменится.
Поэтому я бы сказал, что в большинстве случаев правильный ответ — Stream — он более гибкий, не требует обычно ненужных затрат на материализацию и при необходимости может быть легко превращен в Коллекцию по вашему выбору. Но иногда вам, возможно, придется вернуть Collection (например, из-за строгих требований к согласованности), или вы можете захотеть вернуть Collection, потому что вы знаете, как пользователь будет его использовать, и знаете, что это наиболее удобно для них.
Если у вас уже есть подходящий Collection, и кажется вероятным, что ваши пользователи предпочли бы взаимодействовать с ним как с Collection, то разумным выбором (хотя и не единственным и более хрупким) будет просто вернуть то, что у вас есть.
person
Brian Goetz
schedule
10.07.2014
players.stream()— это именно такой метод, который возвращает поток вызывающей стороне. Реальный вопрос заключается в том, действительно ли вы хотите ограничить вызывающую сторону одним обходом, а также запретить ему доступ к вашей коллекции черезCollectionAPI? Может быть, вызывающий абонент просто хочетaddAllпереместить его в другую коллекцию? - person Marko Topolnik   schedule 10.07.2014