Google Protobuf处理空值


有人向我解释如何在googleprotobuf中处理空值
我有这样的结构:
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message Person {
google.protobuf.DoubleValue age = 4;
}     

和java代码:

DoubleValue myAge = null;
Person build = Person.newBuilder()
.setAge(myAge)  // <- NPE
.build();

此代码导致CCD_ 1行出现空指针异常
那么protobuf DoubleValue的用例是什么?我以为它是用来管理空值的。但是仍然接收到NullPointerException。

你用这样的代码来处理这个问题吗?

DoubleValue a = null;
Person.Builder builder = Person.newBuilder();
if (a != null) {
builder.setAge(a);
}
Person build = builder.build();     

更新:
这是protoc命令生成的代码的一部分:

/**
* <code>.google.protobuf.DoubleValue age = 9;</code>
*/
public Builder setAge(com.google.protobuf.DoubleValue value) {
if (ageBuilder_ == null) {
if (value == null) {        //<-- Additional statement
throw new NullPointerException();
}
age_ = value;
onChanged();
} else {
ageBuilder_.setMessage(value);
}   

为什么在生成的代码中设置额外的if语句
我认为这是google协议缓冲区的一个错误
最后我写了这个代码:

DoubleValue.Builder builder = DoubleValue.newBuilder();
DoubleValue myAge = null;
Person build = Person.newBuilder()
.setAge(myAge != null ? myAge : builder )
.build();

DoubleValue用于处理缺少的值,而不一定是null。Protobuf库旨在从不涉及null——例如,它从不返回null,即使对于丢失的字段也是如此。此外,正如您所发现的,setter不接受null。例如,要清除字段,您应该使用clearField而不是setField(null)

proto2和proto3之间的一个大区别是(最初(";hazzers";对于基元字段(例如hasField(被移除。也就是说,如果您有一个double my_field,则无法判断它是否从未被设置,或者是否被明确设置为零。CCD_ 10在这两种情况下都将返回0。

请注意,消息仍然有hazzer,所以如果您想要该功能,可以将原始字段封装在消息中。这正是.setAge(myAge)1。所以如果你有一个字段DoubleValue age = 1,你可以使用hasAge()来确定它是否被设置。在较新的protobuf版本中,您可以对optional double age = 1执行同样的操作。

请注意,所有这些都与Java生成的代码中的null无关。setter确实不可能接受null值。

TL;DR:你的第一个建议很好,也很常见:

DoubleValue a = null;
Person.Builder builder = Person.newBuilder();
if (a != null) {
builder.setAge(a);
}
Person build = builder.build();     

如果你有一个Optional而不是null,你可以使用一个类似的变体:

OptionalDouble a = OptionalDouble.empty();
Person.Builder builder = Person.newBuilder();
a.ifPresent(value-> builder.getAgeBuilder().setValue(value));
Person build = builder.build();

对于飞镖,您可以将其设置为:

DoubleValue(值:null(

最新更新