以Java 8方式检查对象中包含的空对象和空值
如何将此函数重写为更具可选性的Java 8?还是我应该保持原样以Java 8方式检查对象中包含的空对象和空值,java,arraylist,java-8,optional,Java,Arraylist,Java 8,Optional,如何将此函数重写为更具可选性的Java 8?还是我应该保持原样 public void setMemory(ArrayList<Integer> memory) { if (memory == null) throw new IllegalArgumentException("ERROR: memory object can't be null."); if (memory.contains(null)) throw new Illeg
public void setMemory(ArrayList<Integer> memory) {
if (memory == null)
throw new IllegalArgumentException("ERROR: memory object can't be null.");
if (memory.contains(null))
throw new IllegalArgumentException("ERROR: memory object can't contain null value.");
this.memory = memory;
}
public void setMemory(ArrayList内存){
if(内存==null)
抛出新的IllegalArgumentException(“错误:内存对象不能为null”);
if(memory.contains(null))
抛出新的IllegalArgumentException(“错误:内存对象不能包含空值。”);
这个。记忆=记忆;
}
对于我将使用的第一种情况:
对象。requirennoull()
我不认为
Optional
是一种方法,因为null
是一个非法值。如果您想坚持IllegalArgumentException
并且类路径上有番石榴,您可以使用以下方法:
Preconditions.checkArgument(memory != null,
"ERROR: memory object can't be null.");
Preconditions.checkArgument(!memory.contains(null),
"ERROR: memory object can't contain null value.");
您不能在这里真正使用可选
,因为您需要针对不同的条件显示不同的错误消息
另一方面,如果只有一条错误消息,则可以执行以下操作:
this.memory = Optional.ofNullable(memory)
.filter(x -> !x.contains(null))
.orElseThrow(() -> new IllegalArgumentException(
"memory object is null or contains null values"));
您有一个模式
条件->抛出异常
,可以将其移动到方法:
private void checkOrElseThrow(boolean condition, Supplier<? extends RuntimeException> exceptionSupplier) {
if (condition) {
throw exceptionSupplier.get();
}
}
public void setMemory(List<Integer> memory) {
checkOrElseThrow(memory == null, () -> new IllegalArgumentException("message #1"));
checkOrElseThrow(memory.contains(null), () -> new IllegalArgumentException("message #2"));
this.memory = memory;
}
private void checkorelsetrow(布尔条件,供应商仅当您需要两个不同的异常和更多功能样式时,才可以使用我的解决方案。但它看起来很复杂,甚至更长
.map(e->false)
将列表元素(本例中为整数)映射到布尔值,这是filter()
所需的布尔值
首先,最好使用更通用的列表类型作为输入参数,因此将实现更改为:
public void setMemory(List<Integer> memory) {
//stuff
}
如果您不能使用guava,但仍然不想使用这种方法,那么您可以编写自己的列表实现,为您执行这种空检查
最后,如果所有这些对您来说都不可能,只需保留您的代码。它很容易阅读,而且每个人都知道您在做什么。从这里的其他答案中可以看出,使用选项可能会非常混乱。不要使用选项,它们在这里对您没有好处
取而代之的是使用一个更合适的类型来代替ArrayList。在集合中存储整数会产生(un)装箱成本,并且在不允许空值时没有意义
少数可能的集合库,可以更好地满足您的需求:
HPPC集合(我最喜欢,但API与Java集合框架不兼容)
科洛博克
Fastutil
所有这些库都为原语提供了列表、映射和其他容器的专门实现。这些实现通常比涉及ArrayList
的任何实现都要快得多(除非ArrayList中的所有整数都足够小,可以放入全局Integer
实例缓存)
作为一个很好的副作用,使用基本整数的专用列表在默认情况下不允许调用方存储空值。一个带选项的行:
public void setMemory(ArrayList<Integer> memory) {
this.memory = Optional.ofNullable(memory).map((a) -> Optional.ofNullable(a.contains(null) ? null : a).orElseThrow(() -> new IllegalArgumentException("ERROR: memory object can't contain null value."))).orElseThrow(() -> new IllegalArgumentException("ERROR: memory object can't be null."));
}
public void setMemory(ArrayList内存){
this.memory=Optional.ofNullable(memory).map((a)->Optional.ofNullable(a.contains(null)?null:a).OrelsThrow(()->新的IllegalArgumentException(“错误:内存对象不能包含null值”))).OrelsThrow(()->新的IllegalArgumentException(“错误:内存对象不能为null”);
}
对于这类情况,我通常避免使用可选的
,因为它往往会掩盖正在发生的事情
但首先我要提到的是,原始代码允许调用方保留对包含类的内部字段内存的引用。也许您相信调用方不是恶意的,但调用方可能会意外地重用作为参数传递的列表。如果这样做,尽管进行了细致的参数检查,但内存
列表最终可能包含空值。或者,它可能会意外更改,导致其他故障
解决方案是制作参数列表的防御性副本。简单的方法如下:
public void setMemory(ArrayList<Integer> memory) {
if (memory == null)
throw new IllegalArgumentException("memory is null");
List<Integer> temp = new ArrayList<>(memory);
if (temp.contains(null))
throw new IllegalArgumentException("memory contains null");
this.memory = temp;
}
public void setMemory(ArrayList<Integer> memory) {
List<Integer> temp;
if (memory == null || ((temp = new ArrayList<>(memory)).contains(null)))
throw new IllegalArgumentException("memory is or contains null");
this.memory = temp;
}
现在可以将其重写为使用可选:
public void setMemory(ArrayList<Integer> memory) {
this.memory = Optional.ofNullable(memory)
.map(ArrayList::new)
.filter(list -> ! list.contains(null))
.orElseThrow(() -> new IllegalArgumentException("memory is or contains null"));
}
public void setMemory(ArrayList内存){
this.memory=Optional.ofNullable(内存)
.map(ArrayList::新建)
.filter(列表->!list.contains(null))
.orelsetrow(()->new IllegalArgumentException(“内存为空或包含空”);
}
与通常的滥用相比:-)的Optional
我经常看到,这一个还不错。这里的链接可以避免创建局部变量,这是一种胜利。逻辑相当简单,特别是如果前脑上有可选的
。然而,我会有点担心在一个月内重新访问这段代码。在说服自己它做了你想做的事情之前,你可能得眯着眼睛看一会儿
最后,是一些一般风格的评论
通常的首选(至少在JDK中)是在这些情况下使用NullPointerException
。对于这些示例,我一直坚持使用IllegalArgumentException
,因为OP就是这么用的
我建议对参数类型和字段类型使用List
而不是ArrayList
。这将允许在适当的情况下使用不可修改的列表(例如,使用JDK 9的List.of
)
很抱歉添加了另一个答案,但根据对该问题的阅读评论,可能还有更好的方法来更改该方法的签名:将ArrayList
替换为IntStream
:
public void setMemory(@NonNull IntStream input) {
Objects.requireNonNull(input);
this.memory = ...; // collect the stream into the storage
}
原始流不会产生(取消)装箱的成本
这样,您就不必担心调用者更改您脚下的列表内容,并且可以按照my中的说明为整数选择合适的存储空间(甚至可以懒散地解析流内容!)。如果您仍然希望抛出两个不同的自定义异常,我不知道如何将其缩短。我觉得这很好,我更喜欢h
public void setMemory(ArrayList<Integer> memory) {
List<Integer> temp;
if (memory == null || ((temp = new ArrayList<>(memory)).contains(null)))
throw new IllegalArgumentException("memory is or contains null");
this.memory = temp;
}
public void setMemory(ArrayList<Integer> memory) {
this.memory = Optional.ofNullable(memory)
.map(ArrayList::new)
.filter(list -> ! list.contains(null))
.orElseThrow(() -> new IllegalArgumentException("memory is or contains null"));
}
public void setMemory(@NonNull IntStream input) {
Objects.requireNonNull(input);
this.memory = ...; // collect the stream into the storage
}