Я хочу суммировать список целых чисел. Он работает следующим образом, но синтаксис не кажется правильным. Можно ли оптимизировать код?
Map<String, Integer> integers;
integers.values().stream().mapToInt(i -> i).sum();
Я хочу суммировать список целых чисел. Он работает следующим образом, но синтаксис не кажется правильным. Можно ли оптимизировать код?
Map<String, Integer> integers;
integers.values().stream().mapToInt(i -> i).sum();
Это будет работать, но i -> i
выполняет автоматическую распаковку, поэтому он "чувствует" странность. Любой из следующих действий будет работать и лучше объяснить, что делает компилятор под капотом с вашим исходным синтаксисом:
integers.values().stream().mapToInt(i -> i.intValue()).sum();
integers.values().stream().mapToInt(Integer::intValue).sum();
Я предлагаю еще 2 варианта:
integers.values().stream().mapToInt(Integer::intValue).sum();
integers.values().stream().collect(Collectors.summingInt(Integer::intValue));
Второй использует Collectors.summingInt()
collector, есть коллекционер summingLong()
, который вы использовали бы с mapToLong
.
И третий вариант: Java 8 представляет собой очень эффективный аккумулятор LongAdder
, предназначенный для ускорения суммирования в параллельных потоках и многопоточных сред. Здесь здесь используется пример:
LongAdder a = new LongAdder();
map.values().parallelStream().forEach(a::add);
sum = a.intValue();
Из docs
Операции сокращения Операция сокращения (также называемая сгибом) принимает последовательность входных элементов и объединяет их в один итоговый результат путем повторного применения операции объединения, например, нахождения суммы или максимума набора чисел или накопления элементов в списке, Классы потоков имеют несколько форм операций общей редукции, называемых reduce() и collect(), а также несколько специализированных редукционных форм, таких как sum(), max() или count().
Конечно, такие операции могут быть легко реализованы как простые последовательные циклы, как в:
int sum = 0; for (int x : numbers) { sum += x; }
Однако есть веские причины предпочесть операцию уменьшения по сравнению с мутационным накоплением, таким как выше. Мало того, что сокращение "более абстрактно" - оно работает как с потоком в целом, а не с отдельными элементами, но правильно построенная операция сокращения по своей сути является параллелизуемой, если функции (функции), используемые для обработки элементов, являются ассоциативными и без гражданства. Например, учитывая поток чисел, для которого мы хотим найти сумму, мы можем написать:
int sum = numbers.stream().reduce(0, (x,y) -> x+y);
или
int sum = numbers.stream().reduce(0, Integer::sum);
Эти операции восстановления могут выполняться безопасно параллельно почти без изменений:
int sum = numbers.parallelStream().reduce(0, Integer::sum);
Итак, для карты вы должны использовать:
integers.values().stream().mapToInt(i -> i).reduce(0, (x,y) -> x+y);
Или:
integers.values().stream().reduce(0, Integer::sum);
Вы можете использовать метод уменьшить:
long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, (x, y) -> x + y);
или же
long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, Integer::sum);
Вы можете использовать reduce()
для суммирования списка целых чисел.
int sum = integers.values().stream().reduce(0, Integer::sum);
Вы можете использовать метод сбора, чтобы добавить список целых чисел.
List<Integer> list = Arrays.asList(2, 4, 5, 6);
int sum = list.stream().collect(Collectors.summingInt(Integer::intValue));
Это был бы кратчайший способ суммировать массив типа int
(для long
массива LongStream
, для double
массива DoubleStream
и т.д.). Однако не все примитивные целочисленные типы или типы с плавающей запятой имеют реализацию Stream
.
IntStream.of(integers).sum();
Вы можете попробовать использовать их ниже:
Использование mapToInt
int sum = numberList.stream().mapToInt(Integer::intValue).sum();
Используя summarizingInt
int sum = numberList.stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum();
Используя reduce
int sum = numberList.stream().reduce(Integer::sum).get().intValue();
class Pojo{
int num;
public Pojo(int num) {
super();
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
List<Pojo> list = new ArrayList<Pojo>();
list.add(new Pojo(1));
list.add(new Pojo(5));
list.add(new Pojo(3));
list.add(new Pojo(4));
list.add(new Pojo(5));
int totalSum = list.stream().mapToInt(pojo -> pojo.getNum()).sum();
System.out.println(totalSum);
Большинство аспектов покрыты. Но может возникнуть необходимость найти агрегацию других типов данных, кроме Integer, Long (для которых уже есть поддержка специализированных потоков). Например, для Stram с BigInteger. Для такого типа мы можем использовать операцию
list.stream(). Reduce ((bigInteger1, bigInteger2) → bigInteger1.add(bigInteger2))