详细分析JAVA8新特性 Base64
作者:沃德天拉莫帅 发布时间:2022-07-09 15:41:21
BASE64 编码是一种常用的字符编码,在很多地方都会用到。但base64不是安全领域下的加密解密算法。能起到安全作用的效果很差,而且很容易破解,他核心作用应该是传输数据的正确性,有些网关或系统只能使用ASCII字符。Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法,而且base64特别适合在http,mime协议下快速传输数据。
JDK里面实现Base64的API
在JDK1.6之前,JDK核心类一直没有Base64的实现类,有人建议用Sun/Oracle JDK里面的sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder,使用它们的优点就是不需要依赖第三方类库,缺点就是可能在未来版本会被删除(用maven编译会发出警告),而且性能不佳,后面会有性能测试。
JDK1.6中添加了另一个Base64的实现,javax.xml.bind.DatatypeConverter两个静态方法parseBase64Binary 和 printBase64Binary,隐藏在javax.xml.bind包下面,不被很多开发者知道。
在Java 8在java.util包下面实现了BASE64编解码API,而且性能不俗,API也简单易懂,下面展示下这个类的使用例子。
java.util.Base64
该类提供了一套静态方法获取下面三种BASE64编解码器:
1)Basic编码:是标准的BASE64编码,用于处理常规的需求
// 编码
String asB64 = Base64.getEncoder().encodeToString("some string".getBytes("utf-8"));
System.out.println(asB64); // 输出为: c29tZSBzdHJpbmc=
// 解码
byte[] asBytes = Base64.getDecoder().decode("c29tZSBzdHJpbmc=");
System.out.println(new String(asBytes, "utf-8")); // 输出为: some string
2)URL编码:使用下划线替换URL里面的反斜线“/”
String urlEncoded = Base64.getUrlEncoder().encodeToString("subjects?abcd".getBytes("utf-8"));
System.out.println("Using URL Alphabet: " + urlEncoded);
// 输出为:
Using URL Alphabet: c3ViamVjdHM_YWJjZA==
3)MIME编码:使用基本的字母数字产生BASE64输出,而且对MIME格式友好:每一行输出不超过76个字符,而且每行以“\r\n”符结束。
StringBuilder sb = new StringBuilder();
for (int t = 0; t < 10; ++t) {
sb.append(UUID.randomUUID().toString());
}
byte[] toEncode = sb.toString().getBytes("utf-8");
String mimeEncoded = Base64.getMimeEncoder().encodeToString(toEncode);
System.out.println(mimeEncoded);
第三方实现Base64的API
首先便是常用的Apache Commons Codec library里面的org.apache.commons.codec.binary.Base64;
第二个便是Google Guava库里面的com.google.common.io.BaseEncoding.base64() 这个静态方法;
第三个是net.iharder.Base64,这个jar包就一个类;
最后一个,号称Base64编码速度最快的MigBase64,而且是10年前的实现,到现在是否能保持这个称号,测一测便知道;
Base64编码性能测试
上面讲了一共7种实现Base64编码,Jdk里面3种,第三方实现4种,一旦有选择,则有必要将他们进行一次高低对比,性能测试是最直接的方式
首先来定义两个接口
private static interface Base64Codec
{
public String encode(final byte[] data);
public byte[] decode(final String base64) throws IOException;
}
private static interface Base64ByteCodec
{
public byte[] encodeBytes(final byte[] data);
public byte[] decodeBytes(final byte[] base64) throws IOException;
}
两个接口区别就是其中一个接口方法参数接收byte数组,返回byte数组,因为byte->byte相比String->byte或者byte->String性能上会快一点,所以区分两组来测试
private static final Base64Codec[] m_codecs = { new GuavaImpl(), new JavaXmlImpl(),
new Java8Impl(), new SunImpl(), new ApacheImpl(),new MiGBase64Impl(),new IHarderImpl() };
private static final Base64ByteCodec[] m_byteCodecs = {
new ApacheImpl(), new Java8Impl(),new MiGBase64Impl(),new IHarderImpl() };
从上面看出,其中支持byte->byte只有4中API;
7个Base64的实现类
private static class Java8Impl implements Base64Codec, Base64ByteCodec
{
private final Base64.Decoder m_decoder = Base64.getDecoder();
private final Base64.Encoder m_encoder = Base64.getEncoder();
@Override
public String encode(byte[] data) {
return m_encoder.encodeToString(data);
}
@Override
public byte[] decode(String base64) throws IOException {
return m_decoder.decode(base64);
}
public byte[] encodeBytes(byte[] data) {
return m_encoder.encode( data );
}
public byte[] decodeBytes(byte[] base64) throws IOException {
return m_decoder.decode( base64 );
}
}
private static class JavaXmlImpl implements Base64Codec //no byte[] implementation
{
public String encode(byte[] data) {
return DatatypeConverter.printBase64Binary( data );
}
public byte[] decode(String base64) throws IOException {
return DatatypeConverter.parseBase64Binary( base64 );
}
}
后面代码基本就是各种API实现Base64的代码了,就不详细列出。
主要测试手段是,生成100M的随机数,分成100byte或者1000byte的块,然后将他们分别编码和解码,记录时间,如下方法
private static TestResult testByteCodec( final Base64ByteCodec codec, final List<byte[]> buffers ) throws IOException {
final List<byte[]> encoded = new ArrayList<byte[]>( buffers.size() );
final long start = System.currentTimeMillis();
for ( final byte[] buf : buffers )
encoded.add( codec.encodeBytes(buf) );
final long encodeTime = System.currentTimeMillis() - start;
final List<byte[]> result = new ArrayList<byte[]>( buffers.size() );
final long start2 = System.currentTimeMillis();
for ( final byte[] ar : encoded )
result.add( codec.decodeBytes(ar) );
final long decodeTime = System.currentTimeMillis() - start2;
for ( int i = 0; i < buffers.size(); ++i )
{
if ( !Arrays.equals( buffers.get( i ), result.get( i ) ) )
System.out.println( "Diff at pos = " + i );
}
return new TestResult( encodeTime / 1000.0, decodeTime / 1000.0 );
}
测试结果
jvm参数:-Xms512m -Xmx4G
一切都很明显了,从上面看出,sun的表现不是很好,IHarder和MigBase64性能可以接受,传说MigBase64性能第一,那也是过去了,在这次测试结果中,新的java8 base64运行速度最好,javaXml表现次之。
总结
如果你需要一个性能好,可靠的Base64编解码器,不要找JDK外面的了,java8里面的java.util.Base64以及java6中隐藏很深的javax.xml.bind.DatatypeConverter,他们两个都是不错的选择。
来源:https://my.oschina.net/benhaile/blog/267738


猜你喜欢
- 原本计划这一篇来总结JSP,由于JSP的内容比较多,又想着晚上跑跑步减减肥,所以今天先介绍Filter以及它的使用举例,这样的话还有些时间可
- 目录1、概念相关1.1、概念1.2、解决了什么:1.3、场景:2、简单实现2.1 代码3. netty中的责任链模式4、思考本文先介绍了责任
- 四个主要操作类:JsonConverter 、JsonHelper 、JsonSplit 、AjaxResult一、JsonConverte
- 目录Spring事件驱动源码实战在项目实际开发过程中,我们有很多这样的业务场景:一个事务中处理完一个业务逻辑后需要跟着处理另外一个业务逻辑,
- 引言最近一个朋友正在找工作,他说在笔试题中遇到Equals和==有什么区别的题,当时跟他说如果是值类型的,它们没有区别,如果是引用类型的有区
- 方法引用和构造器引用了解了 Lambda 表达式有一段时间了,但是都没有怎么练习,一直停留在最低层次的了解程度,这对于追求技术进步的人来说确
- 前言在实际开发当中,Spring中bean的属性直接赋值用的不是太多,整理这方面的资料,做一个小结,以备后续更深入的学习。通过配置文件的方式
- Dotnet中嵌入资源(位图、图标或光标等)有两种方式,一是直接把资源文件加入到项目,作为嵌入资源,在代码中通过Assembly的GetMa
- java集合中,list列表应该是我们最常使用的,它有两种常见的实现类:ArrayList和LinkedList。ArrayList底层是数
- git仓库直达List<String> strings = Lists.newArrayList("name=kk&q
- java读取文件内容,解析Json格式数据一、读取txt文件内容(Json格式数据) public static
- 问题背景公司的项目需要前后端分离,vue+java,这时候就需要支持Cors跨域请求了。最近对zuul进行升级,假如说zuul是1.0的话,
- 使用了RecyclerView嵌套RecyclerView的方案。购物车的第一个界面为RecyclerView,每个Item里面包含一个店铺
- java 中基本算法之希尔排序的实例详解希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的
- 自从接触javascript以来,对this参数的理解一直是模棱两可。虽有过深入去理解,但却也总感觉是那种浮于表面,没有完全理清头绪。但对于
- 分页问题是一个非常普遍的问题,开发者几乎都会遇到,这里不讨论具体如何分页,说明一下Web方式下分页的原理。首先是查询获得一个结果集(表现为查
- 封面GitHub传送门1.写在前面本文主要讲的是在Android原生Switch控件的基础上进行样式自定义,内容很简单,但是在实现的过程中还
- 一、前期准备我们要在IDEA上创建一个新的项目,创建好一个项目后,我们需要创建4个包,分别是英雄包,装备包,铭文包,野怪包,皮肤包然后我们就
- 目录为什么要实现调用链跟踪?如何实现?第一步,看图、看场景,用户浏览器的一次请求行为所走的路径是什么样的第二步,实现。不想看代码可直接拉最后
- 前言最近开发中用到许多对话框,之前都是在外面的代码中创建AlertDialog并设置自定义布局实现常见的对话框,诸如更新提示等含有取消和删除