java 如果允许空值,则为三个或更多整数的最大值/最小值

kse8i1jr  于 2023-04-19  发布在  Java
关注(0)|答案(6)|浏览(158)

我想知道是否有一个更好的,简短而优雅的方法来实现这一点比我正在尝试的。假设我有3个整数(value1,value2,value3),我想找到最大值的整数和空值是允许的。我不能使用下面的代码,因为它可能会抛出NullPointerException:

Math.max(Math.max(value1, value2), value3)

我已经写了一个野蛮的代码(如下所示),但它不会超过3个整数:

public Integer getMaxValue(Integer value1, Integer value2, Integer value3) {

    Integer defaultValue = 1;

    if (value1 == null && value2 == null && value3 == null) {
        return defaultValue;
    } else if (value1 == null && value2 != null && value3 != null) {
        return Math.max(value2, value3);
    } else if (value2 == null && value1 != null && value3 != null) {
        return Math.max(value1, value3);
    } else if (value3 == null && value1 != null && value2 != null) {
        return Math.max(value1, value2);
    } else if (value1 == null && value2 == null) {
        return value3;
    } else if (value2 == null && value3 == null) {
        return value1;
    } else if (value1 == null && value3 == null) {
        return value2;
    } else {
        return Math.max(Math.max(value1, value2), value3);
    }
}
mccptt67

mccptt671#

不如

public Integer getMaxValue(Integer... numbers) {
    return Arrays.stream(numbers)
      .filter(Objects::nonNull)
      .max(naturalOrder())
      .orElse(1);
}

它处理任意数量的整数,其中任何一个或所有整数都可以为null。
您可以将其转换为返回Optional<T>而不是T的泛型方法,因为T没有通用的默认值。

public <T extends Comparable<? super T>> Optional<T> getMaxValue(T... numbers) {
    return Arrays.stream(numbers)
      .filter(Objects::nonNull)
      .max(naturalOrder());
}
gajydyqb

gajydyqb2#

我推荐使用Java Streams,它提供了一种非常简洁的方式来过滤空值并返回一个最大值,或者如果所有输入的数字都是空值,则返回默认值。

public Integer getMaxValue( Integer value1, Integer value2, Integer value3 ) {
    Integer defaultValue = 1;

    return Stream.of( value1, value2, value3 ) // create a stream of the values
            .filter( Objects::nonNull ) // filter out the non-null values
            .max( Comparator.naturalOrder() ) // grab the max value
            .orElse( defaultValue ); // if all of the values were null, return the default
}
6ljaweal

6ljaweal3#

这里有一个变体,如果你想要 * 最小值和最大值,并且你有一小部分数据驻留在内存中。

对于最小 * 和最大 *

定义一个record来保存结果。

record MinMax( Integer min , Integer max ) { }

一些示例数据。

List < Integer > integers = List.of( 7 , 99 , 42 , 3 );

在(a)跳过空值和(B)排序之后,从该列表中生成Deque

Deque < Integer > deque =
        integers
                .stream()
                .filter( Objects :: nonNull )
                .sorted()
                .collect( Collectors.toCollection( ArrayDeque :: new ) );

从双端队列中提取第一个(最小值)和最后一个(最大值)。构造一条MinMax记录。

MinMax minMax = new MinMax( deque.peekFirst() , deque.peekLast() );

运行时:
minMax.toString()= MinMax[min=3,max=99]
如果输入列表不包含整数,则MinMax的两个字段都为空。
如果输入列表包含1个整数,则MinMax的两个字段包含相同的数字。
您可能希望向记录中添加一个名为minEqualsMax的方便方法,以查看两个字段是否具有相同的数字或都为null。

record MinMax( Integer min , Integer max ) 
{ 
    boolean minEqualsMax () { return Objects.equals( min , max ) ; }
}

我们可以将deque代码移动到记录MinMax上的静态工厂方法中。我们可以将此方法命名为fromList,但实际上,此代码适用于任何Collection。因此我们将其命名为fromCollection
完整的类示例。

package work.basil.example.minmax;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public record MinMax( Integer min , Integer max )
{
    static MinMax fromCollection ( final Collection < Integer > integers )
    {
        Deque < Integer > deque =
                integers
                        .stream()
                        .filter( Objects :: nonNull )
                        .sorted()
                        .collect( Collectors.toCollection( ArrayDeque :: new ) );
        return new MinMax( deque.peekFirst() , deque.peekLast() );
    }

    boolean minEqualsMax ( ) { return Objects.equals( min , max ); }
}

现在我们可以编写简单的代码,如:

MinMax minMax = MinMax.fromCollection( List.of( 7 , 99 , 42 , 3 ) ) ;

演示代码。

List < List < Integer > > lists =
        List.of(
                List.of( 7 , 99 , 42 , 3 ) ,
                List.of( 42 ) ,
                List.of()
        );
lists.forEach(
        list -> System.out.println( MinMax.fromCollection( list ) )
);

运行时:

MinMax[min=3, max=99]
MinMax[min=42, max=42]
MinMax[min=null, max=null]

警告:如果元素数量非常大,或者元素没有全部加载到内存中,则排序的开销很大。对于这些情况,不要使用本答案的方法。但是对于常见情况,例如处理发票上的行项目,这种方法是合理的。

mm5n2pyu

mm5n2pyu4#

下面是一个使用streams的一行程序解决方案:

Stream.of(value1, value2, value3)
        .filter(Objects::nonNull)
        .reduce(Math::max)
        .orElse(defaultValue);

这将创建一个包含三个值的Stream,过滤掉空值,对元素成对调用Math.max,返回给定值,如果所有值都为空,则返回defaultValue

bq3bfh9z

bq3bfh9z5#

使用先决条件检查:

public Integer getMaxValue(Integer one, Integer two, Integer thr) {
    //Assign nulls min values, or keep if non-null
    one = one == null ? Integer.MIN_VALUE : one;
    two = two == null ? Integer.MIN_VALUE : two;
    thr = thr == null ? Integer.MIN_VALUE : thr;
    //perform comparison on non-null values
    return Math.max(Math.max(one, two), three);
}

通过使用Integer.MIN_VALUE,您可以确保任何其他Integer将大于(或等于)null输入的结果。
应该注意的是,在这种情况下,getMaxValue(null, null, null)将导致Integer.MIN_VALUE。如果你想处理这种情况,那么你可以预先检查所有三个都为null,并相应地返回其他东西。
(Note流解决方案对于N个输入工作良好,但在该特定情况下可能是过度的)。

k0pti3hp

k0pti3hp6#

另一种方法是先对空值进行排序:将你的值添加到一个列表中,按自然顺序排序,首先为null,检查排序后的最后一个元素是否为null,如果是,返回默认值,否则返回最后一个值:

public Integer getMaxValue(Integer... numbers) {

    List<Integer> list = Arrays.asList(numbers);
    list.sort(Comparator.nullsFirst(Comparator.naturalOrder()));

    return list.get(list.size() - 1) == null ? 1 : list.get(list.size() - 1);
}

相关问题