为了账号安全,请及时绑定邮箱和手机立即绑定

OffsetDateTime 的 Java 最快解析器

OffsetDateTime 的 Java 最快解析器

鸿蒙传说 2022-06-08 17:22:07
在 Java 中将日期/时间解析为 OffsetDateTimes 的最快方法是什么?有没有比标准库更快的库?例如OffsetDatetime x = Something.parse("2018-01-02T12:34:56+00:00");
查看完整描述

2 回答

?
达令说

TA贡献1821条经验 获得超6个赞

据我所知,答案是否定的,没有其他库可以将2018-01-02T12:34:56+00:00"(ISO 8601 格式)等字符串解析为OffsetDateTime对象。如果存在的话,我会期望听到或读到它。


我对下一点如履薄冰,但我也认为标准库(AKA java.time)足够高效,并且可能与您期望的一样快。


编辑:我很好奇并编写了自己的 parse 方法,看看我是否能够胜过 one-arg OffsetDateTime.parse。我曾是。我自己的方法(以下来源)没有内置方法的灵活性,它只接受标准格式的大量变体中的一个,这可能是它在性能方面的强项。解析你的字符串一百万次需要:


1.034 秒使用OffsetDateTime.parse

0.117秒用我自己的方法

这不是推荐!我可能永远不会使用我自己的方法。出于绝大多数目的,维护负担是不值得的。如果有一天出现了 ISO 8601 的不同变体,您将遇到昂贵的支持问题和错误修复。


我的方法很简单:


private static final OffsetDateTime parse(String s) {

    char offsetSign;

    if (s.length() != 25

            || s.charAt(4) != '-'

            || s.charAt(7) != '-'

            || s.charAt(10) != 'T'

            || s.charAt(13) != ':'

            || s.charAt(16) != ':'

            || ((offsetSign = s.charAt(19)) != '+' && offsetSign != '-')

            || s.charAt(22) != ':') {

        throw new IllegalArgumentException();

    }

    int offsetHours = Integer.parseInt(s.substring(20, 22));

    int offsetMinutes = Integer.parseInt(s.substring(23, 25));

    if (offsetSign == '-') {

        offsetHours = -offsetHours;

        offsetMinutes = -offsetMinutes;

    }

    return OffsetDateTime.of(Integer.parseInt(s.substring(0, 4)),

            Integer.parseInt(s.substring(5, 7)),

            Integer.parseInt(s.substring(8, 10)), 

            Integer.parseInt(s.substring(11, 13)), 

            Integer.parseInt(s.substring(14, 16)), 

            Integer.parseInt(s.substring(17, 19)), 

            0,

            ZoneOffset.ofHoursMinutes(offsetHours, offsetMinutes));

}

我知道代码中的错误。我认为不值得彻底测试并修复此答案的错误,因为它不太可能对性能产生太大影响。


查看完整回答
反对 回复 2022-06-08
?
呼唤远方

TA贡献1856条经验 获得超11个赞

每次解析不到一毫秒,您不必担心优化解析OffsetDateTime。当然,你必须有更大的鱼来炸。

细节

让我们尝试一个小基准测试。

警告:微基准是出了名的不可靠。但希望这能让我们接近现实的理解。

警告:我匆匆写下这段代码和这篇文章。请仔细检查我的工作。

在我试图避免 JVM 优化运行时的微弱尝试中,我使用了 31 个不同的值,一个用于 1 月份的每一天。我将这些重复一千次以获得 31,000 个列表。然后我洗牌了。

尽管如此,我的结果表明在运行时进行了大量优化。每次解析的纳秒数因循环数而变化很大。

  • 100_000 次循环 = 每次解析 1,573 纳秒(1 微秒)

  • 10_000 = 4,243

  • 1_000 = 10,177

  • 100 = 31,125

  • 1 = 每次解析 693,687 纳秒。(693 微秒,超过半毫秒)。

我使用了 Azul Systems 的 Java 11 JVM Zulu产品,这是一个基于 OpenJDK 版本 11.0.2 的实现。在 MacBook Pro(Retina,15 英寸,2013 年末)、2.3 GHz Intel Core i7、16 GB 1600 MHz DDR3 上运行。

结果总结:

  • 少数几个最坏的情况是每次解析不到一毫秒

  • 最好的情况是每个只有微秒

我的结论:

  • 不要担心解析您的OffsetDateTime输入字符串。

  • 您可能会陷入过早优化的陷阱。

代码。


System.out.println( "INFO - Starting the OffsetDateTime parsing benchmark." );


List < String > inputsShort = new ArrayList <>( 31 );

inputsShort.add( "2018-01-01T12:34:56+00:00" );

inputsShort.add( "2018-01-02T12:34:56+00:00" );

inputsShort.add( "2018-01-03T12:34:56+00:00" );

inputsShort.add( "2018-01-04T12:34:56+00:00" );

inputsShort.add( "2018-01-05T12:34:56+00:00" );

inputsShort.add( "2018-01-06T12:34:56+00:00" );

inputsShort.add( "2018-01-07T12:34:56+00:00" );

inputsShort.add( "2018-01-08T12:34:56+00:00" );

inputsShort.add( "2018-01-09T12:34:56+00:00" );

inputsShort.add( "2018-01-10T12:34:56+00:00" );

inputsShort.add( "2018-01-11T12:34:56+00:00" );

inputsShort.add( "2018-01-12T12:34:56+00:00" );

inputsShort.add( "2018-01-13T12:34:56+00:00" );

inputsShort.add( "2018-01-14T12:34:56+00:00" );

inputsShort.add( "2018-01-15T12:34:56+00:00" );

inputsShort.add( "2018-01-16T12:34:56+00:00" );

inputsShort.add( "2018-01-17T12:34:56+00:00" );

inputsShort.add( "2018-01-18T12:34:56+00:00" );

inputsShort.add( "2018-01-19T12:34:56+00:00" );

inputsShort.add( "2018-01-20T12:34:56+00:00" );

inputsShort.add( "2018-01-21T12:34:56+00:00" );

inputsShort.add( "2018-01-22T12:34:56+00:00" );

inputsShort.add( "2018-01-23T12:34:56+00:00" );

inputsShort.add( "2018-01-24T12:34:56+00:00" );

inputsShort.add( "2018-01-25T12:34:56+00:00" );

inputsShort.add( "2018-01-26T12:34:56+00:00" );

inputsShort.add( "2018-01-27T12:34:56+00:00" );

inputsShort.add( "2018-01-28T12:34:56+00:00" );

inputsShort.add( "2018-01-29T12:34:56+00:00" );

inputsShort.add( "2018-01-30T12:34:56+00:00" );

inputsShort.add( "2018-01-31T12:34:56+00:00" );


int loops = 100; // 100_000=1,573 nanos each parse. 10_000=4,243. 1_000=10,177. 100=31,125. 1=693,687 nanos each parse.

List < String > inputs = new ArrayList <>( inputsShort.size() * loops );

for ( int i = 1 ; i <= loops ; i++ ) {

    inputs.addAll( inputsShort );

}

Collections.shuffle( inputs );

//System.out.println( inputs );


long start = System.nanoTime();

for ( String input : inputs ) {

    OffsetDateTime odt = OffsetDateTime.parse( input );

}

long stop = System.nanoTime();

long nanosPerParse = ( ( stop - start ) / inputs.size() );

System.out.println( "INFO: nanosPerParse: " + nanosPerParse + " for a count of: " + inputs.size() + "." );


查看完整回答
反对 回复 2022-06-08
  • 2 回答
  • 0 关注
  • 125 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号