Java 在每个时间段后更新日期和时间

Java 在每个时间段后更新日期和时间,java,Java,我想为我正在开发的一个小型Java实用程序创建自己的基本控制台日志。一切基本上都是实时运行的;然而,有一小段代码困扰着我。我将简要介绍下面的所有代码 注意:这里几乎所有的代码都未经测试/未优化。如果我做错了什么,请告诉我,我很愿意接受批评 用于日志记录目的的静态变量: static ArrayList<String> logs = new ArrayList<>(); static int offset = 0; static DateFormat dateFormat

我想为我正在开发的一个小型Java实用程序创建自己的基本控制台日志。一切基本上都是实时运行的;然而,有一小段代码困扰着我。我将简要介绍下面的所有代码

注意:这里几乎所有的代码都未经测试/未优化。如果我做错了什么,请告诉我,我很愿意接受批评

用于日志记录目的的静态变量:

static ArrayList<String> logs = new ArrayList<>();
static int offset = 0;
static DateFormat dateFormat = new SimpleDateFormat("yyy/MM/dd HH:mm:ss");
static Date date = new Date();
以下内容每150毫秒自动更新一次控制台:

public static void timerLogging(final JTextArea textArea) {
Timer timer = new Timer(150, new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e)
       {
           updateDateAndTime();
           populateTextArea(textArea);
       }
    });
    timer.start();
}
下面是困扰我的问题:

public static void updateDateAndTime() {
    date = new Date();
}

有没有一种方法可以简单地执行诸如date=GlobalDate.getCurrentDate;?按照目前的设置方式,它是否会产生一点开销?可能甚至不明显,但我不是那种“让它工作起来”的人?

没有开销可言:每秒七次创建一个额外对象不算开销

但是,如果要保留相同的Date对象,可以使用Date的默认构造函数使用的相同方式重新初始化它:


没有开销可谈:每秒七次创建一个附加对象不算开销

但是,如果要保留相同的Date对象,可以使用Date的默认构造函数使用的相同方式重新初始化它:


在同一句话中看到Java和Date时,首先要检查的地方是

java.lang.Date是可变的,因此您可以保留相同的Date对象并更改其表示的日期:

date.setTime(System.currentTimeMillis());
java.lang.Date是可变的这一事实通常被认为是java API设计方式中的一个错误。今天和明天不是同一个日期,它们不应该是同一个对象


Joda Time和Java 8中的新包都大量使用对象。

在同一句话中看到Java和Date时,首先要检查的地方是

java.lang.Date是可变的,因此您可以保留相同的Date对象并更改其表示的日期:

date.setTime(System.currentTimeMillis());
java.lang.Date是可变的这一事实通常被认为是java API设计方式中的一个错误。今天和明天不是同一个日期,它们不应该是同一个对象

Joda Time和Java 8中的新包都大量使用对象。

避免过早优化 正如其他两个答案所指出的,通常您不应该担心在Java中创建对象的开销。至少Oracle提供的实现针对短期对象的创建和销毁进行了高度优化。每秒几次不是问题

在编码一个长时间运行的紧密循环时,您可以简单地考虑重新使用对象。但是,只有当您证明存在性能问题时,才致力于减少实例化。否则,你就会落入错误的陷阱

ISO 8601 该标准为日期时间值的文本表示定义了合理的格式。YYYY-MM-DDTHH:MM:SS.SSSZ格式对于日志记录很有意义

UTC 使用时区中的日期时间值,然后调整到本地时区,以便向用户演示,这几乎总是更好的方法。这意味着您的业务逻辑、数据库存储和日志记录应该在UTC中完成

Joda-Time和java.Time 与java捆绑在一起的java.util.Date和.Calendar类是出了名的麻烦、混乱和缺陷。避开它们

取而代之的是使用这个库,或者是受Joda Time启发的新内置Java8

在生成或解析字符串时,Joda Time和java.Time都使用ISO 8601作为默认值。time类通过在通常的偏移量编号之外附加时区名称来扩展ISO 8601

示例代码–Joda时间 使用Joda Time 2.7的示例代码

DateTime nowUtc = DateTime.now( DateTimeZone.UTC ) ;
示例输出

2013-08-21T00:16:26.941+09:00 要向用户演示,请指定另一个时区

DateTime nowQuébec = nowUtc.withZone( DateTimeZone.forID( "America/Montreal" ) ) ;
ZoneId zone = ZoneId.of("America/Montreal"); 
ZonedDateTime nowQuébec = ZonedDateTime.of( nowUtc , zone ) ;
示例代码–java.time java 8中使用java.time的示例代码

ZonedDateTime nowUtc = ZonedDateTime.now( ZoneOffset.UTC );
示例输出

2013-08-21T00:16:26.941+09:00[亚洲/东京] 调整时区

DateTime nowQuébec = nowUtc.withZone( DateTimeZone.forID( "America/Montreal" ) ) ;
ZoneId zone = ZoneId.of("America/Montreal"); 
ZonedDateTime nowQuébec = ZonedDateTime.of( nowUtc , zone ) ;
乔达时间表演 每秒创建几个实例不是问题

要引用常见问题解答条目

Joda Time专为性能而设计。与java.util.Calendar、java.text.SimpleDataFormat和java.util.TimeZone相比,Joda Time中几乎所有等价的操作都更快。重要的例外是获取或设置单个字段的操作

调用get on java.util.Calendar非常快,因为它不做任何工作。Calendar会提前计算所有字段,即使其中许多字段是您不需要的。Calendar的set方法很快,因为它将计算推迟到以后。调用Calendar.set后调用Calendar.get将强制重新计算所有字段值。在调用DateTime.set之后调用Joda的DateTime.get方法只执行最小数量的计算,并且该对比日历更快

乔达时间也 在操作期间分配很少的临时对象,并且几乎不执行线程同步。在多线程或占用大量内存的系统中,日历、SimpleDataFormat和时区可能成为瓶颈。当使用Joda时间类时,瓶颈就消失了

执行人 您可能希望使用替换,特别是。执行器在很大程度上已经过时了计时器。特别是在Servlet/JavaEEWeb应用程序中,您不应该使用计时器。搜索StackOverflow和Google以获取更多信息

日志框架 如果您的问题确实是关于日志记录的,我建议您学习使用Java中提供的几种好的日志记录框架之一

slf4j 第一步是获得成功。这个项目只是一个接口,一个API抽象

因为Java中有很多日志框架,所以您可能会在不同的项目中遇到不同的框架,或者您可能希望在自己的项目中切换框架。需要注意的是,日志记录意味着您有许多调用散布在整个代码库中。因此,学习或改变框架很麻烦。slf4j项目旨在通过提供一组在代码中调用的接口来解决这个问题。在幕后,适配器介入,将这些slf4j调用转换为特定日志框架的调用。存在用于、Java等的适配器

实际上,slf4j还附带了一个非常简单的接口实现。此实现仅用于开始开发,或用于非常简单的项目。默认情况下,实现只记录其中的一些,但您可以对此进行调整。您可以从这个简单的实现开始,然后切换到Logback;这就是slf4j的全部要点,使您能够切换日志框架

倒退 此外,slf4j的创建者也创建了。Logback是一个功能齐全的日志框架,直接实现slf4j的接口。作为接口的直接实现意味着不需要适配器

顺便说一下,slf4j和Logback的创建者Ceki Gülcü也是著名的log4j的创建者。他利用自己在伐木方面的丰富经验创建了一个继任者,slf4j&Logback

Logback中一个显著的缺陷是它不支持上面提到的日期时间的ISO 8601格式。你可以根据需要调整

对于新项目,我建议从slf4j+Logback开始。对于使用另一个日志框架的现有项目,在通过适配器通过slf4j进行调用时保持该日志框架。将来的某一天,在所有日志调用都被slf4j调用替换之后,如果需要,您可以选择使用Logback替换日志框架。

避免过早优化 正如其他两个答案所指出的,通常您不应该担心在Java中创建对象的开销。至少Oracle提供的实现针对短期对象的创建和销毁进行了高度优化。每秒几次不是问题

在编码一个长时间运行的紧密循环时,您可以简单地考虑重新使用对象。但是,只有当您证明存在性能问题时,才致力于减少实例化。否则,你就会落入错误的陷阱

ISO 8601 该标准为日期时间值的文本表示定义了合理的格式。YYYY-MM-DDTHH:MM:SS.SSSZ格式对于日志记录很有意义

UTC 使用时区中的日期时间值,然后调整到本地时区,以便向用户演示,这几乎总是更好的方法。这意味着您的业务逻辑、数据库存储和日志记录应该在UTC中完成

Joda-Time和java.Time 与java捆绑在一起的java.util.Date和.Calendar类是出了名的麻烦、混乱和缺陷。避开它们

取而代之的是使用这个库,或者是受Joda Time启发的新内置Java8

在生成或解析字符串时,Joda Time和java.Time都使用ISO 8601作为默认值。time类通过在通常的偏移量编号之外附加时区名称来扩展ISO 8601

示例代码–Joda时间 使用Joda Time 2.7的示例代码

DateTime nowUtc = DateTime.now( DateTimeZone.UTC ) ;
示例输出

2013-08-21T00:16:26.941+09:00 要向用户演示,请指定另一个时区

DateTime nowQuébec = nowUtc.withZone( DateTimeZone.forID( "America/Montreal" ) ) ;
ZoneId zone = ZoneId.of("America/Montreal"); 
ZonedDateTime nowQuébec = ZonedDateTime.of( nowUtc , zone ) ;
示例代码–java.time java 8中使用java.time的示例代码

ZonedDateTime nowUtc = ZonedDateTime.now( ZoneOffset.UTC );
示例输出

2013-08-21T00:16:26.941+09:00[亚洲/东京] 调整时区

DateTime nowQuébec = nowUtc.withZone( DateTimeZone.forID( "America/Montreal" ) ) ;
ZoneId zone = ZoneId.of("America/Montreal"); 
ZonedDateTime nowQuébec = ZonedDateTime.of( nowUtc , zone ) ;
乔达时间表演 每秒创建几个实例不是问题

要引用常见问题解答条目

Joda Time专为性能而设计。与java.util.Calendar、java.text.SimpleDataFormat和java.util.TimeZone相比,Joda Time中几乎所有等价的操作都更快。重要的例外是获取或设置单个字段的操作

调用get on java.util.Calendar非常快,因为它不做任何工作。卡尔 endar会提前计算所有字段,即使其中许多字段是您不需要的。Calendar的set方法很快,因为它将计算推迟到以后。调用Calendar.set后调用Calendar.get将强制重新计算所有字段值。在调用DateTime.set之后调用Joda的DateTime.get方法只执行最小数量的计算,并且该对比日历更快

Joda Time还在操作期间分配很少的临时对象,并且几乎不执行线程同步。在多线程或占用大量内存的系统中,日历、SimpleDataFormat和时区可能成为瓶颈。当使用Joda时间类时,瓶颈就消失了

执行人 您可能希望使用替换,特别是。执行器在很大程度上已经过时了计时器。特别是在Servlet/JavaEEWeb应用程序中,您不应该使用计时器。搜索StackOverflow和Google以获取更多信息

日志框架 如果您的问题确实是关于日志记录的,我建议您学习使用Java中提供的几种好的日志记录框架之一

slf4j 第一步是获得成功。这个项目只是一个接口,一个API抽象

因为Java中有很多日志框架,所以您可能会在不同的项目中遇到不同的框架,或者您可能希望在自己的项目中切换框架。需要注意的是,日志记录意味着您有许多调用散布在整个代码库中。因此,学习或改变框架很麻烦。slf4j项目旨在通过提供一组在代码中调用的接口来解决这个问题。在幕后,适配器介入,将这些slf4j调用转换为特定日志框架的调用。存在用于、Java等的适配器

实际上,slf4j还附带了一个非常简单的接口实现。此实现仅用于开始开发,或用于非常简单的项目。默认情况下,实现只记录其中的一些,但您可以对此进行调整。您可以从这个简单的实现开始,然后切换到Logback;这就是slf4j的全部要点,使您能够切换日志框架

倒退 此外,slf4j的创建者也创建了。Logback是一个功能齐全的日志框架,直接实现slf4j的接口。作为接口的直接实现意味着不需要适配器

顺便说一下,slf4j和Logback的创建者Ceki Gülcü也是著名的log4j的创建者。他利用自己在伐木方面的丰富经验创建了一个继任者,slf4j&Logback

Logback中一个显著的缺陷是它不支持上面提到的日期时间的ISO 8601格式。你可以根据需要调整


对于新项目,我建议从slf4j+Logback开始。对于使用另一个日志框架的现有项目,在通过适配器通过slf4j进行调用时保持该日志框架。将来的某一天,在所有日志调用都被slf4j调用替换之后,如果需要,您可以选择使用Logback替换日志框架。

请记住,如果您花时间担心小的开销,你将有更少的时间花在真正重要的事情上。请注意,如果你更改Date实例的值,那么你将为引用同一实例的每个人更改它。Kayaman说得好@Tom-它只用于控制台,我想在这种情况下它确实是安全的。正如旁注-您似乎在使用全局SimpleDataFormat实例和TimerTask。如果您在代码中碰巧使用了多个TimerTask,请记住SimpleDataFormat不是线程安全的,这不是您现在使用的代码的问题,但如果您使用多个TimerTask,则可能会出现问题TimerTasks@KresimirNesek你能详细说明一下吗?我对你想说的话有一个简单的理解,但我没有完全理解。请记住,如果你花时间担心小的管理费用,那么你花在真正重要的事情上的时间就会少得多。请注意,如果你改变日期实例的值,然后你会为所有引用同一实例的人修改它。好观点,卡亚曼@Tom-它只用于控制台,我想在这种情况下它确实是安全的。正如旁注-您似乎在使用全局SimpleDataFormat实例和TimerTask。如果您在代码中碰巧使用了多个TimerTask,请记住SimpleDataFormat不是线程安全的,这不是您现在使用的代码的问题,但如果您使用多个TimerTask,则可能会出现问题TimerTasks@KresimirNesek你能详细说明一下吗?我对你想说的话有一个简单的理解,但我没有完全理解。我确实听说过和读过关于Joda Time的内容,在一年前实际使用它之前,但忘记了它是为了什么。我读过一位著名的乔恩的评论,他说了同样的话,我可以问一下为什么这被认为是一个缺陷吗
我在JavaAPI中?因为您实际上可以更改当前日期?@Juxhin否,问题不在于更改JVM或主机操作系统中时钟的当前时间,因为java.util.Date不能这样做。阅读和谷歌以了解有关不可变对象的更多信息。可变日期的问题在于,您往往会传递日期对象。如果它们是可变的,这意味着它们在您使用它们时可能会发生变化,这在大多数情况下都是出乎意料的。在一年前实际使用Joda time之前,我确实听说并阅读过Joda time,但忘记了为什么。我读到了一位著名的Jon的评论,他说了同样的话,我可以问一下为什么这被认为是JavaAPI中的一个缺陷吗?因为您实际上可以更改当前日期?@Juxhin否,问题不在于更改JVM或主机操作系统中时钟的当前时间,因为java.util.Date不能这样做。阅读和谷歌以了解有关不可变对象的更多信息。可变日期的问题在于,您往往会传递日期对象。如果它们是可变的,这意味着它们在你使用它们时可能会发生变化,这在大多数情况下是出乎意料的。每次你改变日期,小猫都会死亡。我更喜欢您的第一个实现,即每次都创建一个新日期。每个日志都是在不同的时间完成的,它应该是不同的日期对象。@Guillaume-我几乎想问一个关于这个问题的问题,特别是,似乎有很多关于java.lang.Date的评论是有点问题的。然而,我确信已经有很多问题了。@Juxhin我希望java.util.Date是不可变的,但是由于设计者不赞成除setTime之外的所有变异方法,我认为他们有意使类保持可变。尽管如此,我并不赞同“垂死的小猫”原则:我认为使用API的所有功能是可以的,即使你在哲学上不同意它的设计者的观点:好吧,就我的预期用途而言,它似乎工作得很好,所以我将保持这种方式。我确实理解他们的观点,并在一定程度上同意这一点。再次感谢大家的投入。每次你改变约会,小猫都会死去。我更喜欢您的第一个实现,即每次都创建一个新日期。每个日志都是在不同的时间完成的,它应该是不同的日期对象。@Guillaume-我几乎想问一个关于这个问题的问题,特别是,似乎有很多关于java.lang.Date的评论是有点问题的。然而,我确信已经有很多问题了。@Juxhin我希望java.util.Date是不可变的,但是由于设计者不赞成除setTime之外的所有变异方法,我认为他们有意使类保持可变。尽管如此,我并不赞同“垂死的小猫”原则:我认为使用API的所有功能是可以的,即使你在哲学上不同意它的设计者的观点:好吧,就我的预期用途而言,它似乎工作得很好,所以我将保持这种方式。我确实理解他们的观点,并在一定程度上同意这一点。再次感谢大家的意见。非常感谢你们的inpit Basil,你们提出了一些非常好的观点。现在,我剥离了应用程序的整个日志方面,并考虑以ypur方式重新实现它,或者简单地使用log4j。不,不是log4j,那是上个千年的事。看看一个API抽象,只是接口和实现。哈哈,是的,1993年或者类似的东西确实有点过时了。我确实检查了SLF4J,所以我将使用logback实现它,或者再次,只编写我自己的非常基本的一个,因为我不需要任何详细说明。然而,我确实希望学习如何在我未来的应用程序中正确地实现SLF4J。实际上,SLF4J包括一个非常简单的实现,可以满足您的需要。默认情况下,它只记录一些优先级,但您可以进行调整。另外,有趣的是,slf4j和logback是由log4j的发明者创建的。这让我不禁要问,为什么log4j还在使用关于SLF4J,我会诚实地说,在实现外国API方面,我非常软弱。我一次又一次地抱怨它们有多么重要,但我发现自己总是使用纯JavaAPI,这一点我并不自豪。所以我只需要强迫自己离开舒适区,开始使用SLF4J。感谢您提供的大量提示和精彩帖子。我只需要将它标记为正确的答案。非常感谢你的inpit Basil,你提出了一些非常好的观点。现在,我剥离了应用程序的整个日志方面,并考虑以ypur方式重新实现它,或者简单地使用log4j。不,不是log4j,那是上个千年的事。看看一个API抽象,只是接口和实现。哈哈,是的,1993年或者类似的东西确实有点过时了。我确实检查了SLF4J,所以我将使用logback实现它,或者再次,只编写我自己的非常基本的一个,因为我不需要任何详细说明。然而,我确实希望学习在我未来的应用程序中正确地实现SLF4J
实际上,slf4j包含一个非常简单的实现,可以满足您的需要。默认情况下,它只记录一些优先级,但您可以进行调整。另外,有趣的是,slf4j和logback是由log4j的发明者创建的。这让我不禁要问,为什么log4j还在使用关于SLF4J,我会诚实地说,在实现外国API方面,我非常软弱。我一次又一次地抱怨它们有多么重要,但我发现自己总是使用纯JavaAPI,这一点我并不自豪。所以我只需要强迫自己离开舒适区,开始使用SLF4J。感谢您提供的大量提示和精彩帖子。我只是把它标记为正确的答案。