Jim*_*m C 2 lambda stream optional higher-order-functions java-8
上下文:我有一个Web服务,它返回一个带有menbers的家庭.一个家庭将永远有一个父亲和一个母亲,没有孩子或多个孩子.该服务在下面由wsdl描述.
目的:我想有效地使用Java 8中的Optional,并避免使用经典方法来检查null.经典,我的意思是我们习惯于在Java 7之前完成的方式.
如果我假设webservice将始终返回一个家庭,这就足够了:
@Test
public void test1() {
Family f = helloWorldClientImplBean.allFamily();
f.getChildren().stream().filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
}
Run Code Online (Sandbox Code Playgroud)
我测试了,我可以看到,只要我得到一个家庭通过服务回答,如果我有孩子,这将完全无关紧要.我的意思是,在下面的服务实现中,如果我评论了oldSon和youngSon代码,那么根本就没有null异常.
当服务返回null时,问题会引发.
在阅读了几篇博客并讨论了它之后,我得到了这个代码,它正确地检查了服务的返回是否为空.
@Test
public void testWorkingButSeemsOdd() {
//Family f = helloWorldClientImplBean.allFamily();
Family f = null; //to make simple the explanation
Optional<Family> optFamily = Optional.ofNullable(f);
if (optFamily.isPresent()) {
optFamily.filter(Objects::nonNull).map(Family::getChildren).get().stream().filter(Objects::nonNull)
.filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println("Optional: " + y.getLastName()));
}
Run Code Online (Sandbox Code Playgroud)
对我来说更干净的是这些方法中的一种(所有这些方法都令人费解,但我相信它们可以展示我一直在尝试做的事情):
//这里我尝试在映射之前过滤f是否为null
@Test
public void testFilterNonNull() {
Family f = null;
Optional.ofNullable(f).filter(Objects::nonNull).map(Family::getChildren).get().stream().filter(Objects::nonNull)
.filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
}
Run Code Online (Sandbox Code Playgroud)
我知道下一个没有编译,但我想有可能达到类似的东西
@Test
@Ignore
public void testOptionalNullable() {
Family f = helloWorldClientImplBean.allFamily();
Optional.ofNullable(f).orElse(System.out.println("Family is null")).map(Family::getChildren).get().stream().filter(Objects::nonNull)
.filter(x -> x.getFirstName().equalsIgnoreCase("John")).findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
}
Run Code Online (Sandbox Code Playgroud)
WSDL
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions targetNamespace="http://codenotfound.com/services/helloworld"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://codenotfound.com/services/helloworld"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="HelloWorld">
<wsdl:types>
<schema targetNamespace="http://codenotfound.com/services/helloworld"
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://codenotfound.com/services/helloworld"
elementFormDefault="qualified" attributeFormDefault="unqualified"
version="1.0">
<element name="family">
<complexType>
<sequence>
<element name="father" type="tns:persontype" minOccurs="1"
maxOccurs="1" />
<element name="mother" type="tns:persontype" minOccurs="1"
maxOccurs="1" />
<element name="children" type="tns:persontype" minOccurs="0"
maxOccurs="unbounded" />
</sequence>
</complexType>
</element>
<complexType name="persontype">
<sequence>
<element name="firstName" type="xsd:string" />
<element name="lastName" type="xsd:string" />
</sequence>
</complexType>
<element name="EmptyParameter" type="tns:voidType" />
<complexType name="voidType">
<sequence />
</complexType>
</schema>
</wsdl:types>
<!-- Message -->
<wsdl:message name="emptyRequest">
<wsdl:part name="emptyParameter" element="tns:EmptyParameter" />
</wsdl:message>
<wsdl:message name="allFamiliesResponse">
<wsdl:part name="allFamiliesResponse" element="tns:family" />
</wsdl:message>
<!-- PortType -->
<wsdl:operation name="allFamilies">
<wsdl:input message="tns:emptyRequest" />
<wsdl:output message="tns:allFamiliesResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<!-- Binding -->
<wsdl:binding name="HelloWorld_Binding" type="tns:HelloWorld_PortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="allFamilies">
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloWorld_Service">
<wsdl:port name="HelloWorld_Port" binding="tns:HelloWorld_Binding">
<soap:address location="http://localhost:9090/cnf/services/helloworld" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Run Code Online (Sandbox Code Playgroud)
服务实施的相关部分:
@Override
public Family allFamilies(VoidType emptyParameter) {
ObjectFactory factory = new ObjectFactory();
Family result = factory.createFamily();
Persontype father = new Persontype();
father.setFirstName("Jose");
father.setLastName("Pereira");
Persontype mother = new Persontype();
mother.setFirstName("Maria");
mother.setLastName("Pereira");
result.setFather(father);
result.setMother(mother);
Persontype olderSon = new Persontype();
olderSon.setFirstName("John");
olderSon.setLastName("Pereira");
Persontype youngerSon = new Persontype();
youngerSon.setFirstName("Ana");
youngerSon.setLastName("Pereira");
result.getChildren().add(olderSon);
result.getChildren().add(youngerSon);
return result;
}
Run Code Online (Sandbox Code Playgroud)
所以,我的直接问题是:基于WSDL和其实施上述我的方案,是检查是否从Web服务返回的是空在我们习惯做的一个非常相似的方式使用isPresent()真正唯一途径经典的空检查(if(f!= null){...)?
主要的误解是假设需要.filter(Objects::nonNull)在可选项上执行操作.如果空选项需要这样的过滤,那将会击败期权的全部目的.特别是,当谓词评估时,过滤的结果再次是一个空的可选项false,使你回到原点1.
事实上,.filter(Objects::nonNull)具有相同的效果.filter(x -> true),对于非空自选它一直true为空自选它永远不会无论如何评价.
此外,if尽管您已经了解,但您正在切换回声明ifPresent.因此,从您的原始代码派生的一个直接解决方案将是
Optional.ofNullable(helloWorldClientImplBean.allFamily())
.ifPresent(f -> f.getChildren().stream()
.filter(x -> x.getFirstName().equalsIgnoreCase("John"))
.findFirst()
.ifPresent(y -> System.out.println(y.getLastName()));
Run Code Online (Sandbox Code Playgroud)
您可以通过将操作更改为减少嵌套部分
Optional.ofNullable(helloWorldClientImplBean.allFamily())
.flatMap(f -> f.getChildren().stream()
.filter(x -> x.getFirstName().equalsIgnoreCase("John"))
.findFirst())
.ifPresent(y -> System.out.println(y.getLastName()));
Run Code Online (Sandbox Code Playgroud)
这只解决了您在问题中描述的问题,即服务allFamily()可能会返回null.您还在null流操作中包含了一个新检查,该检查将处理子实例所在的情况null.
如果确实需要这样做,那么最好的解决方案就是对负责服务实施的任何人进行抨击,但无论如何,第二个最好的解决方案就是简单地做
Optional.ofNullable(helloWorldClientImplBean.allFamily())
.flatMap(f -> f.getChildren().stream()
.filter(x -> x!=null && x.getFirstName().equalsIgnoreCase("John"))
.findFirst())
.ifPresent(y -> System.out.println(y.getLastName()));
Run Code Online (Sandbox Code Playgroud)
这比.filter(Objects::nonNull)在流中插入附加内容更简单.
| 归档时间: |
|
| 查看次数: |
63 次 |
| 最近记录: |