Задача: реализовать сервис/утилиту для суммирования элементов массива/коллекции безопасно и эффективно.
Подход: один проход по входным данным (O(n) по времени, O(1) дополнительной памяти). Для обычных массивов int используем накопитель типа long чтобы избежать переполнения при сумме; при необходимости возвращаем int с контролем переполнения. Для задач, где возможны очень большие числа, предоставляем вариант с BigInteger. Сделаем методы статическими (утилитарный класс) — просто и удобно для тестирования.
long, строгий int (с проверкой переполнения) и произвольно большая точность с BigInteger.Ниже — утилитарный класс и JUnit5 тесты. Положим оба файла в пакет com.test.
// package declaration
package com.test;
import java.math.BigInteger;
import java.util.List;
import java.util.Objects;
/**
* Утилитарный класс для суммирования коллекций/массивов.
* Методы статические, без состояния.
*/
public final class ArraySumCalculator {
private ArraySumCalculator() {}
/**
* Суммирует int[] и возвращает результат в long (во избежание overflow).
* Временная сложность O(n).
*/
public static long sumIntsToLong(int[] arr) {
Objects.requireNonNull(arr, "arr must not be null");
long sum = 0L;
for (int v : arr) {
sum += v;
}
return sum;
}
/**
* Суммирует int[] и возвращает int, но бросает ArithmeticException при переполнении.
*/
public static int sumInts(int[] arr) {
long sum = sumIntsToLong(arr);
if (sum > Integer.MAX_VALUE || sum < Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow when summing array (sum = " + sum + ")");
}
return (int) sum;
}
/**
* Суммирует long[] и возвращает результат в long (может переполниться по long — в этом случае
* пользователь может использовать sumLongToBigInteger).
*/
public static long sumLongs(long[] arr) {
Objects.requireNonNull(arr, "arr must not be null");
long sum = 0L;
for (long v : arr) {
sum += v;
}
return sum;
}
/**
* Суммирует long[] и возвращает BigInteger — безопасно для любых сумм.
*/
public static BigInteger sumLongsToBigInteger(long[] arr) {
Objects.requireNonNull(arr, "arr must not be null");
BigInteger sum = BigInteger.ZERO;
for (long v : arr) {
sum = sum.add(BigInteger.valueOf(v));
}
return sum;
}
/**
* Суммирует произвольный список Number, используя BigInteger (устойчиво к большим значениям).
* Null-элементы внутри списка игнорируются (можно изменить поведение, если нужно).
*/
public static BigInteger sumNumbersToBigInteger(List extends Number> numbers) {
Objects.requireNonNull(numbers, "numbers must not be null");
BigInteger sum = BigInteger.ZERO;
for (Number n : numbers) {
if (n == null) continue;
// Вариант: использовать значение longValue() — это даёт последовательность суммирования по long
// Если нужен полный контроль типов (например BigDecimal), можно расширить метод.
sum = sum.add(BigInteger.valueOf(n.longValue()));
}
return sum;
}
}
package com.test;
import static org.junit.jupiter.api.Assertions.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("ArraySumCalculator Tests")
class ArraySumCalculatorTest {
@Test
void sumsSimpleIntArrayToInt() {
int[] arr = {1, 2, 3};
assertEquals(6, ArraySumCalculator.sumInts(arr));
}
@Test
void sumsIntArrayToLongAvoidOverflow() {
int[] arr = {Integer.MAX_VALUE, 1};
long expected = (long) Integer.MAX_VALUE + 1L;
assertEquals(expected, ArraySumCalculator.sumIntsToLong(arr));
}
@Test
void sumLongsToBigIntegerForVeryLargeSums() {
long[] arr = {Long.MAX_VALUE, 1L};
BigInteger expected = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
assertEquals(expected, ArraySumCalculator.sumLongsToBigInteger(arr));
}
@Test
void sumNumberListToBigIntegerIgnoresNullElements() {
List list = Arrays.asList(1, null, 2, 3);
BigInteger expected = BigInteger.valueOf(6);
assertEquals(expected, ArraySumCalculator.sumNumbersToBigInteger(list));
}
@Test
void sumIntsThrowsOnNull() {
assertThrows(NullPointerException.class, () -> ArraySumCalculator.sumIntsToLong(null));
}
@Test
void sumIntsThrowsOnOverflow() {
int[] arr = {Integer.MAX_VALUE, Integer.MAX_VALUE};
assertThrows(ArithmeticException.class, () -> ArraySumCalculator.sumInts(arr));
}
}
- Для обычных задач (сумма int без сильного риска переполнения) используйте sumInts(int[]).
- Если хотите быть спокойны насчёт переполнения используйте sumIntsToLong(int[]).
- Для больших сумм (например, суммирование long, которые могут превышать диапазон long) используйте sumLongsToBigInteger(long[]) или sumNumbersToBigInteger(List<Number>).
double и реализацией Kahan summation для повышения точности.Stream<Number> и суммирующие лениво.