Возникает вопрос о том, должны ли java-методы возвращать Collections или Streams, в котором Брайан Гетц отвечает, что даже для конечных последовательностей Streams обычно предпочтительнее.
Но мне кажется, что в настоящее время многие операции над потоками, которые приходят из других мест, не могут быть безопасно выполнены, и защитные средства защиты кода невозможны, потому что потоки не показывают, являются ли они бесконечными или неупорядоченными.
Если параллель была проблемой для операций, которые я хочу выполнить в Stream(), я могу вызвать isParallel() для проверки или последовательно, чтобы убедиться, что вычисления выполняются параллельно (если я не забуду).
Но если упорядоченность или ограниченность (размерность) были важны для безопасности моей программы, я не могу написать гарантии.
Предполагая, что я использую библиотеку, реализующую этот вымышленный интерфейс:
public interface CoordinateServer {
public Stream<Integer> coordinates();
// example implementations:
// IntStream.range(0, 100).boxed() // finite, ordered, sequential
// final AtomicInteger atomic = new AtomicInteger();
// Stream.generate(() -> atomic2.incrementAndGet()) // infinite, unordered, sequential
// Stream.generate(() -> atomic2.incrementAndGet()).parallel() // infinite, unordered, parallel
}
Тогда какие операции я могу безопасно вызвать в этом потоке, чтобы написать правильный алгоритм?
Кажется, если я, возможно, захочу записать элементы в файл как побочный эффект, мне нужно беспокоиться о параллельности потока:
// if stream is parallel, which order will be written to file?
coordinates().peek(i -> {writeToFile(i)}).count();
// how should I remember to always add sequential() in such cases?
А также, если он параллелен, на основании чего Threadpool это параллельно?
Если я хочу отсортировать поток (или другие операции без короткого замыкания), мне нужно быть осторожным, так как он бесконечен:
coordinates().sorted().limit(1000).collect(toList()); // will this terminate?
coordinates().allMatch(x -> x > 0); // will this terminate?
Я могу наложить ограничение перед сортировкой, но какое магическое число это должно быть, если я ожидаю конечный поток неизвестного размера?
Наконец, возможно, я хочу вычислить параллельно, чтобы сэкономить время, а затем собрать результат:
// will result list maintain the same order as sequential?
coordinates().map(i -> complexLookup(i)).parallel().collect(toList());
Но если поток не упорядочен (в этой версии библиотеки), результат может стать искаженным из-за параллельной обработки. Но как я могу защититься от этого, кроме как не использовать параллель (что отрицательно сказывается на производительности)?
Коллекции явно являются конечными или бесконечными, имеют ли они порядок или нет, и они не несут с собой режим обработки или пулы потоков. Это похоже на ценные свойства для API.
Кроме того, потоки иногда могут быть закрыты, но чаще всего нет. Если я использую поток из метода (или из параметра метода), я должен вообще вызвать close?
Кроме того, потоки, возможно, уже были использованы, и было бы хорошо иметь возможность изящно обработать этот случай, поэтому было бы хорошо проверить, был ли поток уже использован;
Я хотел бы получить фрагмент кода, который можно использовать для проверки предположений о потоке перед его обработкой, например>
Stream<X> stream = fooLibrary.getStream();
Stream<X> safeStream = StreamPreconditions(
stream,
/*maxThreshold or elements before IllegalArgumentException*/
10_000,
/* fail with IllegalArgumentException if not ordered */
true
)