Объединение нескольких потоков Java в структурированном виде - PullRequest
0 голосов
/ 24 апреля 2018

Я хочу использовать потоковый API Java для выполнения некоторых вычислений в списке объектов:

List<Item>.stream()...

Класс Item содержит много атрибутов.Для некоторых из них мне нужно взять среднее значение по всем элементам в коллекции, для других атрибутов мне нужно сделать другие формы расчетов.Я делал отдельные вызовы потоков / сборщиков, чтобы достичь этого, и хотя я не сталкиваюсь с какими-либо проблемами с производительностью (поскольку размер списка обычно составляет около 100), я хочу научиться быть более кратким, то есть зацикливаться один раз.

ItemCalculation itemCalculation = ItemCalculation.builder()
    .amountOfItems(itemList.size())
    .averagePrice(itemList.stream()
            .mapToDouble(item -> item.getPrice())
            .average()
            .getAsDouble())
    .averageInvestmentValue(itemList.stream()
            .mapToDouble(item -> getTotalInvestmentValue(item.getInvestmentValue(), item.getInvestmentValuePackaging()))
            .average()
            .getAsDouble())
    .highestWarrantyLimit(itemList.stream()... etc.

Я читал о создании настраиваемого коллектора, но кажется немного странным, что мой класс «вычислений» состоит из одной строки (stream-> customCollector), а затем имеет очень раздутый класс коллектора, который делаетактуальная логика.Тем более, что разные атрибуты собираются по-разному, мне нужно много разных промежуточных счетчиков и других переменных.Есть мысли?

1 Ответ

0 голосов
/ 14 сентября 2018

К сожалению, невозможно разумно улучшить его с помощью потоков, чтобы он мог работать лучше в однопоточном режиме.

Код, который вы указали в своем вопросе, понятен для понимания и достаточно эффективен для небольшой коллекции, как сейчас.

Если вы хотите повысить производительность своего решения, вы можете выполнить итерацию по своей коллекции всего один раз итеративным способом, вычисляя каждый необходимый результат за один прогон:

    long amountOfItems = 0;
    double priseSum = 0;
    double highestWarrantyLimit = Double.MIN_VALUE;
    for (Item item : itemList) {
        amountOfItems++;
        priseSum += item.getPrice();
        double investmentValue = getTotalInvestmentValue(item.getInvestmentValue(), item.getInvestmentValuePackaging());
        if (highestWarrantyLimit < investmentValue) {
            highestWarrantyLimit = investmentValue;
        }
    }
    ItemCalculation itemCalculation = ItemCalculation.builder()
            .amountOfItems(amountOfItems)
            .averagePrice(priseSum / amountOfItems)
            .averageInvestmentValue(investmentValueSum / amountOfItems)
            .highestWarrantyLimit(highestWarrantyLimit)
            // ...
            .build(); 

Был добавлен API потоков, чтобы обеспечить поддержку библиотек для обработки последовательностей элементов данных, что очень верно для вашего случая. Тем не менее, потоки навязывают общий конвейер для элементов данных, что неверно для вашего случая и делает конвейер похожим на:

itemList.stream()
    .collect(toItemCalculation());

Что не очень разумно, если только вы не собираетесь использовать его в многопоточном режиме. В таком случае было бы предпочтительнее решение, использующее пользовательский коллектор, поскольку код скаффолдинга для объединения логики уже встроен.

...