Math.max: примеры (JAVA)
Math.max(int a, int b): intОписание Math.max()
В Java Math.max - это набор статических перегруженных методов в классе java.lang.Math, предназначенных для выбора большего из двух примитивных числовых значений. Методы доступны для типов int, long, float и double. Сигнатуры выглядят примерно так: int max(int a,int b), long max(long a,long b), float max(float a,float b), double max(double a,double b).
Возвращаемое значение имеет тот же примитивный тип, что и параметры. Поведение при особых значениях для плавающей точки:
- Если один из аргументов типа
floatилиdoubleравенNaN, результат будетNaN. - При сравнении +0.0 и -0.0 результатом будет +0.0, так как +0 считается больше по правилу сравнения IEEE 754, применяемому в Java.
При передаче смешанных литералов или выражений с разными типами применяются правила приведения типов и перегрузки: если один аргумент является long, другой int, будет выбрана версия с long, при этом int неявно приводится. При передаче обёрток (Integer, Long и т. п.) происходит автеразупаковка в примитивы; при значении null возможен NullPointerException.
Класс Math содержит также аналогичные методы в StrictMath, а примитивные классы-обёртки предлагают свои «max»-методы (см. раздел альтернатив).
Короткие примеры использования
Несколько простых примеров для разных перегрузок и ситуаций.
Пример для int:
int a = 5;
int b = 9;
System.out.println(Math.max(a, b));
9
Пример для long с автоматическим повышением типа:
System.out.println(Math.max(1, 2L)); // int и long
2
Поведение с double и NaN:
double x = Double.NaN;
double y = 1.0;
System.out.println(Math.max(x, y));
NaN
Сравнение знаковых нулей:
double p = +0.0;
double n = -0.0;
System.out.println(Math.max(p, n));
System.out.println(1 / Math.max(p, n)); // показать знак нуля
0.0 Infinity
Ошибка при автеразупаковке (null в обёртке):
Integer ai = null;
System.out.println(Math.max(ai, 1));
java.lang.NullPointerException
Аналоги внутри Java и когда их выбирать
Несколько вариантов выбора максимального значения в Java, отличных от Math.max:
- Integer.max, Long.max, Double.max и Float.max - статические методы обёрток, выполняющие ту же задачу для соответствующих примитивов. Подходящи при явно используемых типах и для читабельности.
- Collections.max - выбирает максимум в коллекции объектов, требует, чтобы элементы реализовали
Comparableили передатьComparator. Полезно для списков и наборов объектов. - Stream.max и примитивные стримы (
IntStream.max(),DoubleStream.max()) - удобны при поиске максимума в потоках данных, возвращают Optional-значения. - BigInteger.max и BigDecimal.max - методы экземпляров для больших целых и десятичных чисел; следует применять при необходимости точной арифметики без плавающей точки.
- StrictMath.max - функционально эквивалентен
Math.max, применяется там, где требуется поведение, полностью совместимое с эталонной реализацией.
Аналоги в других языках и отличия
Краткие примеры подходящих аналогов в популярных языках и важные отличия.
JavaScript (переменное число аргументов):
// JS
console.log(Math.max(1, 5, 3));
console.log(Math.max());
console.log(Math.max(1, NaN));
5 -Infinity NaN
Python (функция max для итерируемых и нескольких аргументов):
# Python
print(max(1, 5, 3))
print(max([2, 7, 4]))
5 7
PHP (функция max):
// PHP
echo max(1, 4, 2);
4
C# (Math.Max):
// C#
System.Console.WriteLine(System.Math.Max(1, 3));
System.Console.WriteLine(System.Math.Max(double.NaN, 1.0));
3 NaN
Go (пакет math для float64):
// Go
import "math"
fmt.Println(math.Max(1.0, 2.5))
2.5
Kotlin (функция maxOf и kotlin.math.max):
// Kotlin
println(maxOf(1, 3))
println(kotlin.math.max(1.0, 2.0))
3 2.0
Lua (math.max):
-- Lua
print(math.max(1, 8, 5))
8
SQL (GREATEST, поведение с NULL зависит от СУБД):
-- PostgreSQL/MySQL
SELECT GREATEST(1, 4, 2);
SELECT GREATEST(NULL, 1, 2);
3 NULL
Отличия от Java:
- Во многих языках функция принимает переменное число аргументов (JS, Python, PHP, Lua), тогда как Java Math.max - только бинарная.
- Поведение с NaN и NULL/None/NaN различается: в JS Math.max() при отсутствии аргументов возвращает -Infinity, а в Python вызов без аргументов вызывает ошибку.
- В Go стандартная функция работает только с
float64; для целых типов нужен каст или своя реализация. - SQL-функции работают с NULL по правилам конкретной СУБД, часто возвращают NULL при наличии NULL-аргумента.
Типичные ошибки и подводные камни
Некоторые распространённые ошибки при работе с Math.max и примеры:
NullPointerException при автеразупаковке:
Integer x = null;
int y = 5;
System.out.println(Math.max(x, y));
java.lang.NullPointerException
Ожидание работы с массивом напрямую (нет вариативной версии):
int[] arr = {1, 4, 2};
// неверно: Math.max(arr); // компиляция не пройдёт
Ошибка компиляции: нет подходящей перегрузки
Неочевидное поведение при сравнениях с NaN и знаковыми нулями:
System.out.println(Math.max(Double.NaN, 1.0));
System.out.println(Math.max(+0.0, -0.0));
NaN 0.0
Погрешности при работе с float/double, приводящие к кажущемуся «неправильному» максимуму (обычно связано с представлением чисел с плавающей точкой):
float a = 0.1f + 0.2f;
float b = 0.3f;
System.out.println(a == b);
System.out.println(Math.max(a, b));
false 0.30000004
Изменения в последних версиях Java
Сам Math.max как набор перегрузок для примитивов не претерпевал существенных изменений в недавних релизах. Более заметные изменения связаны с дополнениями в стандартной библиотеке:
- В Java 8 появились статические методы max в обёртках, таких как
Integer.maxиLong.max, что повышает удобство при работе с примитивами и повышает выразительность кода. - Поведение
Math.maxосталось совместимым с предыдущими версиями Java, включая обработку NaN и знаковых нулей.
Расширенные примеры и редкие сценарии
Несколько более сложных и практических примеров применения при обработке данных и в алгоритмах.
Нахождение максимума в массиве с использованием цикла и Math.max:
int[] arr = {3, 7, 2, 9, 5};
int max = Integer.MIN_VALUE;
for (int v : arr) {
max = Math.max(max, v);
}
System.out.println(max);
9
Использование IntStream и ссылки на метод:
int[] nums = {4, 1, 8, 3};
int max = java.util.Arrays.stream(nums).reduce(Math::max).orElse(Integer.MIN_VALUE);
System.out.println(max);
8
Клиппинг (ограничение значения диапазоном) с помощью вложенных вызовов:
int clamp = Math.max(0, Math.min(value, 100));
// value будет приведено к диапазону [0,100]
(в зависимости от value)
Максимум для больших чисел с использованием BigInteger:
java.math.BigInteger a = new java.math.BigInteger("12345678901234567890");
java.math.BigInteger b = new java.math.BigInteger("9876543210987654321");
System.out.println(a.max(b));
12345678901234567890
Использование в динамическом программировании и рекуррентных формулах (пример для одной итерации):
// при вычислении максимальной стоимости пути
int keep = 10; // текущий выбор
int take = 15; // другой вариант
int best = Math.max(keep, take);
System.out.println(best);
15
Поиск максимума в коллекции объектов через Comparator (альтернатива для объектов):
class Person { int age; Person(int a){age=a;} int getAge(){return age;} }
java.util.List list = java.util.List.of(new Person(20), new Person(35), new Person(28));
Person oldest = java.util.Collections.max(list, java.util.Comparator.comparingInt(Person::getAge));
System.out.println(oldest.getAge());
35
Обработка NaN перед сравнением (если требуется игнорировать NaN и выбирать реальное число):
double a = Double.NaN;
double b = 2.0;
double safeMax = Double.isNaN(a) ? b : (Double.isNaN(b) ? a : Math.max(a, b));
System.out.println(safeMax);
2.0