我有一段Java代码,它从可选#map的输入参数中包含的集合中删除一个元素
boolean ret = methodReturnsOptioanl()
.map(project -> project.getDocIds().remove(docId))
.orElse(false);
where项目。getDocId()返回一组字符串ID,并保证不为null。
我已经测试过它并有效;如果选项为空或docId不存在于集合中,ret为false。
但是,可选#map是否可以执行此操作并更改成员集的状态并返回Set#删除操作的布尔结果?
我到处找了找,找不到关于这件事的确切答案。
这样使用map()可以吗?不,因为map()
表达了将可选元素转换为新类型的意图,而这不是您要做的。
虽然没有要求map()
操作没有副作用,并且您的原始代码会做您想要的事情,但它并没有做人们对map()
的期望。未来的读者可能需要重新审视一下才能理解您的代码在做什么。我建议一些更明显的东西:
var project = methodReturnsOptional();
boolean ret = project.isPresent() && project.get().getDocIds().remove(docId);
我会说不,最好的方法是将您的项目
映射到分配给您的项目
Object的docIds
,然后调用终端操作Stream#orElse
。此终端操作应该构造一个新的(Mutable)List/Collection,然后您可以从中删除docId
。
这样,您的代码将如下所示:
boolean ret = optionalVal
.map(Class::getDocIds)
.orElse(new ArrayList<>())
.remove(docId);
但是,一个更节省内存的解决方案是:
boolean ret = optionalVal
.map(Class::getDocIds)
.orElseGet(ArrayList::new)
.remove(docId);
这与这样一个事实有关,即只有当变量为空时,才会调用提供给可选#或lseget
的供应商。当您使用可选的orElse时,将始终调用此方法,并且使用此方法将构造一个空的(可能是不必要的)ArrayList,并将其加载到堆中。这意味着,当可选对象不为空时,可以根据需要构造两倍的对象,而不是只构造一个。
解释
Stream#map
方法是一个中间操作,这意味着它将Stream转换为另一个流。事实并非如此。为此,您可以将orElse
操作用作终端操作,它会生成一个List
/Object
作为结果,以便您删除您的对象ID。
解释内存高效解决方案
当值不存在时,可选的OrelGet仅调用供应商。运行以下测试以验证这一点:
public class TestTest {
class TestOptional {
public TestOptional(){
System.out.println("TestOptional constructor called.. " + this);
}
List<String> getDocIds(){
System.out.println("TestOptional#getDocIds called.. " + this);
return new ArrayList<>(Collections.singletonList("test"));
}
List<String> getEmptyDocIds(){
System.out.println("TestOptional#getEmptyDocIds called.. " + this);
return new ArrayList<>();
}
}
@Test(expected = Exception.class)
public void test() throws Exception {
Optional<TestOptional> optionalVal = Optional.of(new TestOptional());
Optional<TestOptional> optionalValEmpty = Optional.empty();
boolean deleted = optionalVal
.map(TestOptional::getDocIds)
.orElse(new TestOptional().getEmptyDocIds())
.remove("test");
System.out.println("One: " + deleted);
System.out.println("\n ### \n");
boolean deletedTwo = optionalVal
.map(TestOptional::getDocIds)
.orElseGet(() -> new TestOptional().getEmptyDocIds())
.remove("test");
System.out.println("Two: " + deletedTwo);
System.out.println("\n ### \n");
boolean deletedThree = optionalValEmpty
.map(TestOptional::getDocIds)
.orElse(new TestOptional().getEmptyDocIds())
.remove("test");
System.out.println("Three: " + deletedThree);
System.out.println("\n ### \n");
boolean deletedFour = optionalValEmpty
.map(TestOptional::getDocIds)
.orElseGet(() -> new TestOptional().getEmptyDocIds())
.remove("test");
System.out.println("Four: " + deletedFour);
assertThat(deleted).isTrue();
assertThat(deletedTwo).isTrue();
assertThat(deletedThree).isFalse();
assertThat(deletedFour).isFalse();
}
}
测试输出:
TestOptional constructor called.. test.TestTest$TestOptional@28f67ac7
TestOptional#getDocIds called.. test.TestTest$TestOptional@28f67ac7
TestOptional constructor called.. test.TestTest$TestOptional@1a407d53
TestOptional#getEmptyDocIds called.. test.TestTest$TestOptional@1a407d53
One: true
###
TestOptional#getDocIds called.. test.TestTest$TestOptional@28f67ac7
Two: true
###
TestOptional constructor called.. test.TestTest$TestOptional@3cda1055
TestOptional#getEmptyDocIds called.. test.TestTest$TestOptional@3cda1055
Three: false
###
TestOptional constructor called.. test.TestTest$TestOptional@79b4d0f
TestOptional#getEmptyDocIds called.. test.TestTest$TestOptional@79b4d0f
Four: false
然而:如果此代码使用时间短,并且使用频率不高(如方法的使用量),这不会产生太大的影响,因为此方法可能很快就会超出范围。然而,垃圾收集器还有更多的工作要做,这意味着对存储字节的不必要滥用。
问题内容: 在Python中,是否可以在运行时重新定义函数的默认参数? 我在这里定义了带有3个参数的函数: 接下来,我尝试(未成功)设置y的默认参数值,然后尝试调用不带参数的函数: 但是由于未正确设置默认值,所以产生了以下错误: 正如我在此尝试的那样,是否可以在运行时重新定义函数的默认参数? 问题答案: 只需使用functools.partial 这里的一个问题:您将无法调用它,因为您应该手动说
我想知道OpenCV是否能够将摄像头(dev/video1)设置为复合或S-video输入。 我使用的摄像头仅在复合输入中运行,但默认情况下,v4l2在S-Video输入中打开dev/video1。V4l2能够通过QT V4l2 utils应用程序从S视频转换为复合输入。 opencv正在使用v4l从相机捕获图像,我想在代码中使用OpenCV更改为复合输入。那有可能吗?如果不是,解决办法是什么?
本文向大家介绍将数据写入块后是否可以更改数据?相关面试题,主要包含被问及将数据写入块后是否可以更改数据?时的应答技巧和注意事项,需要的朋友参考一下 回答:不,这是不可能的。如果需要进行任何修改,组织也必须从所有其他模块中删除信息。
问题内容: 的 多重嵌套视图 功能非常好-您可以轻松地从应用程序的一种 状态 跳到另一种 状态 。 有时您可能想更改URL,但有时不需要。我觉得 状态 的概念应该与 route 分开/可选。 这是一个说明我意思的朋克。 这是文档中的一个小工具的分支,下面有2个小更改: 这似乎可行-URL保持不变。同样,这里做了多少多余的工作?这是经过批准/测试的用法吗? 如果您可以省略某个州的信息,那就太好了。
可选类应该改变它持有的对象的状态吗?或者每个返回流的中间操作都不应该改变对象的可变性?示例: 当包含实例变量时,是否应用相同的原则。例如
问题内容: 与在或中使用的方式类似: 问题答案: 是。 如果你不理会关键字参数,这很简单并且可以工作: 如你所见,Python将为你提供一个包含所有参数的元组。 对于关键字参数,你需要将其作为单独的实际参数接受,如的所示。