我有这样的结构:
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(