自己写了一个JsonLib

本文介绍了一种自研的JSON编码器和解码器,通过对不同数量级的数据进行性能测试,展示了该工具在小规模数据处理上的优势。同时,针对现有开源库的不足进行了改进。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自己写了一个Json的编码器和解码器
下面的地址是对比用的json-lib项目
[url]http://json-lib.sourceforge.net/[/url]
下面是部分测试比较

/*
* Copyright 2010 Sandy Zhang
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

/**
*
*/
package org.javazone.jroi.framework.coder;

import net.sf.json.JSONObject;

import org.javazone.jroi.framework.coder.json.JsonValue;
import org.javazone.jroi.framework.coder.json.encode.DefaultJsonEncoder;

/**
* @author Sandy Zhang
*/
public class JsonTest
{
public static void main(String[] args)
{

TestBean tb = null;
DefaultJsonEncoder encoder = new DefaultJsonEncoder();
for (int i = 0; i < 100; i++)
{
tb = new TestBean();
JSONObject.fromObject(tb);
encoder.encodeBean(tb).toJsonString();
}
int count = 10000;
tb = tb.init();
// 以上代码为预热代码

double a = System.currentTimeMillis();
for (int i = 0; i < count; i++)
{
JSONObject.fromObject(tb);
}
double c1 = System.currentTimeMillis() - a;
// 以上为JSON_LIB编码。。。先不论其编码架构怎么样
a = System.currentTimeMillis();
for (int i = 0; i < count; i++)
{
new DefaultJsonEncoder().encodeBean(tb).toJsonString();
}
double c2 = System.currentTimeMillis() - a;
// 以上为我自己写的Json_encoder
System.out.println("test count = " + count);
System.out.println("JSON ENCODER use time : " + c1 + " ms");
System.out.println("JROI_JSON ENCODER use time : " + c2 + " ms");
System.out.println("(JROI_JSON is faster than JSON_LIB)rate : "
+ ((c1 / c2) - 1) * 100 + "%");
System.out.println();
// 下面是一次调用的微毫秒级别的比较
a = System.nanoTime();
JSONObject o1 = JSONObject.fromObject(tb);
double c = System.nanoTime() - a;
System.out.println("JSON_LIB run once use time " + c + " ns");
a = System.nanoTime();
JsonValue o2 = new DefaultJsonEncoder().encodeBean(tb);
c = System.nanoTime() - a;
System.out.println("JROI_JSON run once use time " + c + " ns");
}
}

下面是测试结果
[code]
test count = 10
JSON ENCODER use time : 46.0 ms
JROI_JSON ENCODER use time : 16.0 ms
(JROI_JSON is faster than JSON_LIB)rate : 187.5%

JSON_LIB run once use time 2517448.0 ns
JROI_JSON run once use time 977297.0 ns
[/code]
[code]
test count = 100
JSON ENCODER use time : 199.0 ms
JROI_JSON ENCODER use time : 93.0 ms
(JROI_JSON is faster than JSON_LIB)rate : 113.9784946236559%

JSON_LIB run once use time 731587.0 ns
JROI_JSON run once use time 517284.0 ns
[/code]
[code]
test count = 1000
JSON ENCODER use time : 664.0 ms
JROI_JSON ENCODER use time : 663.0 ms
(JROI_JSON is faster than JSON_LIB)rate : 0.15082956259426794%

JSON_LIB run once use time 392889.0 ns
JROI_JSON run once use time 405821.0 ns
[/code]
[code]
test count = 10000
JSON ENCODER use time : 4335.0 ms
JROI_JSON ENCODER use time : 6089.0 ms
(JROI_JSON is faster than JSON_LIB)rate : -28.806043685334203%

JSON_LIB run once use time 452007.0 ns
JROI_JSON run once use time 406438.0 ns
[/code]
[code]
test count = 100000
JSON ENCODER use time : 42517.0 ms
JROI_JSON ENCODER use time : 71011.0 ms
(JROI_JSON is faster than JSON_LIB)rate : -40.126177634451%

JSON_LIB run once use time 389195.0 ns
JROI_JSON run once use time 516668.0 ns
[/code]
首先,预热是相同的,应该不存在误差

因为我使用了许多对象,所以在大量创建对象的情况下,我的效率将被降低,因为JVM的垃圾回收机制
但是在一万次一下的比较中,我的编码程序占据优势,我相信很少情况有大于一千个对象被编码为Json字符串

比较客观的比较应该在100次比较的位置,我也尝试过编写简单的Bean进行测试,我的编码器同样占据速度上的优势,OK,我们看解码

我的结果是生成Map,然后通过接口传递到Handler中进行下一步处理,这样可以将算法与处理进行分离


/*
* Copyright 2010 Sandy Zhang
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

/**
*
*/
package org.javazone.jroi.framework.coder;

import java.util.Map;

import net.sf.json.JSONObject;

import org.javazone.jroi.framework.coder.json.JsonObject;
import org.javazone.jroi.framework.coder.json.decode.analyze.AnalyzeEvent;
import org.javazone.jroi.framework.coder.json.decode.analyze.AnalyzeHandler;
import org.javazone.jroi.framework.coder.json.decode.analyze.JsonAnalyzer;

/**
* @author Sandy Zhang
*/
public class DecodeTest
{
public static class TestAnalyzeHandler
implements AnalyzeHandler
{

@Override
public void endAnalyze(AnalyzeEvent e)
{
// Map<String, Object> map = (Map<String, Object>) e.getResult();
// System.out.println(map.get("name"));
// Object[] objs = (Object[]) map.get("subBeans");
// System.out.println(objs.length);
// for (Object object : objs)
// {
// System.out.println(object);
// }
}

@Override
public void startAnalyze(AnalyzeEvent e)
{
// System.out.println("start");
}
}

public static void main(String[] args)
{
for (int i = 0; i < 5; i++)
{

JsonAnalyzer analyzer = new JsonAnalyzer();
analyzer.addAnalyzeHandler(new TestAnalyzeHandler());
JsonEncoder encoder = Coder.newJsonEncoder();
JsonObject jsonObj =
(JsonObject) encoder.encodeBean(new TestBean().init());

String jsonStr = jsonObj.toJsonString();
JSONObject.fromObject(jsonStr);
// System.out.println(jsonStr);
analyzer.analyze(jsonStr);
}
// 预热代码
int count = 10;

JsonEncoder encoder = Coder.newJsonEncoder();
JsonObject jsonObj =
(JsonObject) encoder.encodeBean(new TestBean().init());

String jsonStr = jsonObj.toJsonString();
// 产生
long a = System.currentTimeMillis();
for (int i = 0; i < count; i++)
{
JsonAnalyzer analyzer = new JsonAnalyzer();
analyzer.addAnalyzeHandler(new TestAnalyzeHandler());
analyzer.analyze(jsonStr);
}
long b = System.currentTimeMillis();
System.out.println(b - a);
// 以上为我自己写的解码器

a = System.currentTimeMillis();
for (int i = 0; i < count; i++)
{
JSONObject.fromObject(jsonStr);
}
b = System.currentTimeMillis();
System.out.println(b - a);
// 以上为Json lib 解码方法
}
}

这是10次的结果
[code]
21
102
[/code]
这是100次的结果
[code]
139
467
[/code]
这是1000次的结果
[code]
484
3450
[/code]
这是10000次的结果
[code]
4217
39873
[/code]
10万次,我不愿意比较了。。。。。。这个已经能够说明问题了。。

当然,不要指望net.sf.json.JSONObject工具会帮助你解码的很完善,fromObject出来的一样是map甚至是他自己创建的结构,并且不支持单一对象的编解码。
例如简单的字符串,比如我不发送对象,只是一个字符串,那么它就做不到,只会给你抛出一个异常。
不知道有人用这个工具包没有,至少我发现这个工具包很差,所以不得已自己写工具包

其次。。。也就是他的toBean方法,在处理泛型的时候不可能转换为确定的类型。

例如:TestBean里有一个List,装载的是SubBean,那么它不会很智能的给你转换为SubBean而是转换为了他自己的Bean,当你使用这个TestBean里的List的时候就等着java.lang.ClassCastException吧Orz.....

下面我把源码包发上来
----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------
v1是最新版本

:cry: 看来编程是白学了。。。居然有个BUG,大家如果愿意用的话帮我找找,看还有BUG没有,我已经审查了算法很多遍了。。。

下面是一个例子,怎么用的例子

package org.javazone.jroi.framework.coder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class TestBean
{

private Collection<TestSubBean> beans = new ArrayList<TestSubBean>();

public Collection<TestSubBean> getBeans()
{
return beans;
}

public void setBeans(Collection<TestSubBean> beans)
{
this.beans = beans;
}

public Set<TestSubBean> getTestSet()
{
return testSet;
}

public void setTestSet(Set<TestSubBean> testSet)
{
this.testSet = testSet;
}

public TestSubBean getTestSubBean()
{
return testSubBean;
}

public void setTestSubBean(TestSubBean testSubBean)
{
this.testSubBean = testSubBean;
}

public List<TestSubBean> getList()
{
return list;
}

public void setList(List<TestSubBean> list)
{
this.list = list;
}

private Set<TestSubBean> testSet = new HashSet<TestSubBean>();

private TestSubBean testSubBean = new TestSubBean();

private List<TestSubBean> list = new ArrayList<TestSubBean>();

public TestBean init()
{
beans.add(new TestSubBean());
testSet.add(new TestSubBean());
list.add(new TestSubBean());
return this;
}

}


/*
* Copyright 2010 Sandy Zhang
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

/**
*
*/
package org.javazone.jroi.framework.coder;

public class TestSubBean
{
private static int currentid = 0;

private String testString =
"this is my sub bean : id = " + Integer.toString(++currentid);

private String testNull = null;

private Integer intTest = Integer.MAX_VALUE;

private Long longTest = Long.MAX_VALUE;

private Double doubleObjectTest = Double.MAX_VALUE;

private Float floatObjectTest = Float.MAX_VALUE;

public void setTestNull(String testNull)
{
this.testNull = testNull;
}

public String getTestNull()
{
return testNull;
}

public void setIntTest(Integer intTest)
{
this.intTest = intTest;
}

public Integer getIntTest()
{
return intTest;
}

public void setLongTest(Long longTest)
{
this.longTest = longTest;
}

public Long getLongTest()
{
return longTest;
}

public void setDoubleObjectTest(Double doubleObjectTest)
{
this.doubleObjectTest = doubleObjectTest;
}

public Double getDoubleObjectTest()
{
return doubleObjectTest;
}

public void setFloatObjectTest(Float floatObjectTest)
{
this.floatObjectTest = floatObjectTest;
}

public Float getFloatObjectTest()
{
return floatObjectTest;
}

public void setTestString(String testString)
{
this.testString = testString;
}

public String getTestString()
{
return testString;
}

}


/*
* Copyright 2010 Sandy Zhang
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

/**
*
*/
package org.javazone.jroi.framework.coder;

import java.util.Arrays;

/**
* @author Sandy Zhang
*/
public class JsonTest
{
public static void main(String[] args)
{
JsonEncoder encoder = Coder.newJsonEncoder();
String jsonString = encoder.encodeBean(new TestBean().init()).toJsonString();
System.out.println(jsonString);
JsonDecoder decoder = Coder.newJsonDecoder();
TestBean bean =
(TestBean) decoder.decodeBean(jsonString, TestBean.class);
System.out.println(bean.getTestSubBean().getTestNull());
System.out.println(bean.getTestSubBean().getTestString());
System.out.println(bean.getTestSubBean().getDoubleObjectTest());
System.out.println(bean.getTestSubBean().getFloatObjectTest());
System.out.println(bean.getTestSubBean().getIntTest());
System.out.println(bean.getTestSubBean().getLongTest());
System.out.println(Arrays.toString(bean.getList().toArray()));
System.out.println(Arrays.toString(bean.getTestSet().toArray()));
System.out.println(Arrays.toString(bean.getList().toArray()));

}
}

[code]
{"beans":[{"longTest":9223372036854775807,"floatObjectTest":3.4028235E38,"intTest":2147483647,"testString":"this is my sub bean : id = 2","doubleObjectTest":1.7976931348623157E308,"testNull":null}],"testSubBean":{"longTest":9223372036854775807,"floatObjectTest":3.4028235E38,"intTest":2147483647,"testString":"this is my sub bean : id = 1","doubleObjectTest":1.7976931348623157E308,"testNull":null},"list":[{"longTest":9223372036854775807,"floatObjectTest":3.4028235E38,"intTest":2147483647,"testString":"this is my sub bean : id = 4","doubleObjectTest":1.7976931348623157E308,"testNull":null}],"testSet":[{"longTest":9223372036854775807,"floatObjectTest":3.4028235E38,"intTest":2147483647,"testString":"this is my sub bean : id = 3","doubleObjectTest":1.7976931348623157E308,"testNull":null}]}
null
this is my sub bean : id = 1
1.7976931348623157E308
3.4028235E38
2147483647
9223372036854775807
[org.javazone.jroi.framework.coder.TestSubBean@52fe85]
[org.javazone.jroi.framework.coder.TestSubBean@1e0cf70]
[org.javazone.jroi.framework.coder.TestSubBean@52fe85]
[/code]

如果有大大愿意给小弟讲下架构就太好了。。。因为我最后发现最开始版本的Handler没用,我也考虑使用Builder模式在算法过程中使用Builder进行对象数组创建,但是都失败了,因为这个问题是个递归问题,递归在栈上不好做文章,确实要考虑就真的只有换非递归算法才能更好的使用设计模式里的算法分离了。。。。哎

至于效率,我也没测试了,看了jackson的实现后,我深深的自卑了 :cry:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值