我想在 Java 中将 String 解析为内部 JSON 对象(或等效对象)。平常的图书馆,Gson
and Jackson
,对于我的需求来说太慢了(根据我的基准,每个字符串到 Json 解析> 100us)。我知道有稍微快一点的库,但是查看在线基准测试,可用的收益将很小(小于一个数量级的改进)。
如果我提前知道 JSON 的格式,有没有办法可以更快地解析它?例如,我知道字符串将是以下格式的 JSON:
{
"A" : 1.0 ,
"B" : "X"
}
即,我知道两个键将是“A”和“B”,值将分别是双精度型和字符串。鉴于这种格式的高级知识,是否有一个库或某种方法可以比平常更快地解析 JSON?
如果你知道一个JSON
您可以使用的有效负载结构Streaming API
读取数据。我创建了 4 种不同的方法来阅读给定的内容JSON
有效负载:
- 默认 Gson - 使用
Gson
class.
- Gson 适配器 - 使用
JsonReader
来自 Gson 库。
- 默认 Jackson - 使用
ObjectMapper
来自杰克逊。
- Jackson 流媒体 API - 使用
JsonParser
class.
To make it comparable all these methods take JSON
payload as String
and return Pojo
object which represents A
and B
properties. Below graph represents differences: ![enter image description here](https://i.stack.imgur.com/uQlmV.png)
正如你所注意到的,Jackson
's Streaming API
是反序列化最快的方法JSON
来自这 4 种方法的有效负载。
为了生成上图,使用了以下数据:
1113 547 540 546 544 552 547 549 547 548 平均 603.3
940 455 452 456 465 459 457 458 455 455 平均 505.2
422 266 257 262 260 267 259 262 257 259 平均 277.1
202 186 184 189 185 188 182 186 187 183 平均 187.2
基准代码:
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class JsonApp {
private static final String json = "{\"A\" : 1.0 ,\"B\" : \"X\"}";
private static final int MAX = 1_000_000;
private static List<List<Duration>> values = new ArrayList<>();
static {
IntStream.range(0, 4).forEach(i -> values.add(new ArrayList<>()));
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
int v = 0;
values.get(v++).add(defaultGson());
values.get(v++).add(gsonAdapter());
values.get(v++).add(defaultJackson());
values.get(v).add(jacksonJsonFactory());
}
values.forEach(list -> {
list.forEach(d -> System.out.print(d.toMillis() + " "));
System.out.println(" avg " + list.stream()
.mapToLong(Duration::toMillis)
.average().getAsDouble());
});
}
static Duration defaultGson() {
Gson gson = new Gson();
long start = System.nanoTime();
for (int i = MAX; i > 0; i--) {
gson.fromJson(json, Pojo.class);
}
return Duration.ofNanos(System.nanoTime() - start);
}
static Duration gsonAdapter() throws IOException {
PojoTypeAdapter adapter = new PojoTypeAdapter();
long start = System.nanoTime();
for (int i = MAX; i > 0; i--) {
adapter.fromJson(json);
}
return Duration.ofNanos(System.nanoTime() - start);
}
static Duration defaultJackson() throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
long start = System.nanoTime();
for (int i = MAX; i > 0; i--) {
mapper.readValue(json, Pojo.class);
}
return Duration.ofNanos(System.nanoTime() - start);
}
static Duration jacksonJsonFactory() throws IOException {
JsonFactory jfactory = new JsonFactory();
long start = System.nanoTime();
for (int i = MAX; i > 0; i--) {
readPartially(jfactory);
}
return Duration.ofNanos(System.nanoTime() - start);
}
static Pojo readPartially(JsonFactory jfactory) throws IOException {
try (JsonParser parser = jfactory.createParser(json)) {
Pojo pojo = new Pojo();
parser.nextToken(); // skip START_OBJECT - {
parser.nextToken(); // skip A name
parser.nextToken();
pojo.A = parser.getDoubleValue();
parser.nextToken(); // skip B name
parser.nextToken();
pojo.B = parser.getValueAsString();
return pojo;
}
}
}
class PojoTypeAdapter extends TypeAdapter<Pojo> {
@Override
public void write(JsonWriter out, Pojo value) {
throw new IllegalStateException("Implement me!");
}
@Override
public Pojo read(JsonReader in) throws IOException {
if (in.peek() == com.google.gson.stream.JsonToken.NULL) {
in.nextNull();
return null;
}
Pojo pojo = new Pojo();
in.beginObject();
in.nextName();
pojo.A = in.nextDouble();
in.nextName();
pojo.B = in.nextString();
return pojo;
}
}
class Pojo {
double A;
String B;
@Override
public String toString() {
return "Pojo{" +
"A=" + A +
", B='" + B + '\'' +
'}';
}
}
注意:如果您需要真正精确的数据,请尝试使用优秀的基准测试来创建基准测试JMH包裹。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)