网站建设储蓄卡,公众号开发收费价目表,怎么添加网站白名单,企点是干嘛用的1. Math.round(11.5)等于多少#xff1f;Math.round(- 11.5) 又等于多少? Math.round(11.5)的返回值是 12#xff0c;Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5然后进行取整。 2. switch 是否能作用在 byte 上#xff0c;是否能作用在 long 上… 1. Math.round(11.5)等于多少Math.round(- 11.5) 又等于多少? Math.round(11.5)的返回值是 12Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5然后进行取整。 2. switch 是否能作用在 byte 上是否能作用在 long 上是否能作用在 String上? Java5以前switch(expr)中expr 只能是 byte、short、char、int。从 Java 5 开始Java 中引入了枚举类型expr 也可以是 enum 类型。 从Java 7 开始expr 还可以是字符串String但是长整型long在目前所有的版本中都是不可以的。 3. 数组有没有length() 方法String有没有length() 方法 数组没有 length()方法而是有 length 的属性。String 有 length()方法。JavaScript 中获得字符串的长度是通过 length 属性得到的这一点容易和 Java 混淆。 4. String 、StringBuilder 、StringBuffer的区别 Java平台提供了两种类型的字符串String和StringBuffer/StringBuilder它们都可以储存和操作字符串区别如下。 1String是只读字符串也就意味着String引用的字符串内容是不能被改变的。初学者可能会有这样的误解 1. String str “abc” 2. str “bcd”; 如上字符串str明明是可以改变的呀其实不然str仅仅是一个引用对象它指向一个字符串对象“abc”。第二行代码的含义是让 str 重新指向了一个新的字符串“bcd”对象而“abc”对象并没有任何改变只不过该对象已经成为一个不可及对象罢了。 2StringBuffer/StringBuilder表示的字符串对象可以直接进行修改。 3StringBuilder是Java5中引入的它和 StringBuffer的方法完全相同区别在于它是在单线程环境下使用的因为它的所有方法都没有被synchronized修饰因此它的效率理论上也比StringBuffer要高。 5. 什么情况下用“”运算符进行字符串连接比调用 StringBuffer/StringBuilder 对象的append方法连接字符串性能更好 该题来自华为。 字符串是Java程序中最常用的数据结构之一。在Java中String类已经重载了。也就是说字符串可以直接使用进行连接如下面代码所示 1String s abc ddd; 但这样做真的好吗当然这个问题不能简单地回答 yes or no。要根据具体情况来定。在 Java 中提供了一个StringBuilder类这个类只在J2SE5及以上版本提供以前的版本使用StringBuffer类这个类也可以起到的作用。那么我们应该用哪个呢 下面让我们先看看如下的代码 1. package string; 2. 3. public class TestSimplePlus 4. { 5. public static void main(String[] args) 6. { 7. String s abc; 8. String ss ok s xyz 5; 9. System.out.println(ss); 10. } 11. } 上面的代码将会输出正确的结果。从表面上看对字符串和整型使用号并没有什么区别但事实真的如此吗 下面让我们来看看这段代码的本质。 我们首先使用反编译工具如jdk带的javap、或jad将TestSimplePlus反编译成Java Byte Code其中的奥 秘就一目了然了。在本文将使用jad来反编译命令如下 jad -o -a -s d.java TestSimplePlus.class 反编译后的代码如下 1. package string; 2. 3. import java.io.PrintStream; 4. 5. public class TestSimplePlus 6. { 7. public TestSimplePlus() 8. { 9. // 0 0:aload_0 10. // 1 1:invokespecial #8 Method void Object() 11. // 2 4:return 12. } 13. 14. public static void main(String args[]) 15. { 16. String s abc; 17. // 0 0:ldc1 #16 String abc 18. // 1 2:astore_1 19. String ss (new StringBuilder(ok)).append(s).append(xyz).append(5).toString(); 20. // 2 3:new #18 Class StringBuilder 21. // 3 6:dup 22. // 4 7:ldc1 #20 String ok 23. // 5 9:invokespecial #22 Method void StringBuilder(String) 24. // 6 12:aload_1 25. // 7 13:invokevirtual #25 Method StringBuilder StringBuilder.append(String) 26. // 8 16:ldc1 #29 String xyz 27. // 9 18:invokevirtual #25 Method StringBuilder StringBuilder.append(String) 28. // 10 21:iconst_5 29. // 11 22:invokevirtual #31 Method StringBuilder StringBuilder.append(int) 30. // 12 25:invokevirtual #34 Method String StringBuilder.toString() 31. // 13 28:astore_2 32. System.out.println(ss); 33. // 14 29:getstatic #38 Field PrintStream System.out 34. // 15 32:aload_2 35. // 16 33:invokevirtual #44 Method void PrintStream.println(String) 36. // 17 36:return 37. } 38. } 读者可能看到上面的Java字节码感到迷糊不过大家不必担心。本文的目的并不是讲解Java Byte Code因此 并不用了解具体的字节码的含义。 使用 jad 反编译的好处之一就是可以同时生成字节码和源代码。这样可以进行对照研究。从上面的代码很容易看 出虽然在源程序中使用了但在编译时仍然将转换成StringBuilder 。因此我们可以得出结论在Java中 无论使用何种方式进行字符串连接实际上都使用的是StringBuilder。 那么是不是可以根据这个结论推出使用和StringBuilder的效果是一样的呢这个要从两个方面的解释。如果 从运行结果来解释那么和StringBuilder是完全等效的。但如果从运行效率和资源消耗方面看那它们将存在很 大的区别。 当然如果连接字符串行表达式很简单如上面的顺序结构那么和StringBuilder基本是一样的但如果 结构比较复杂如使用循环来连接字符串那么产生的 Java Byte Code 就会有很大的区别。先让我们看看如下的代 码 1. package string; 2. 3. import java.util.*; 4. 5. public class TestComplexPlus 6. { 7. public static void main(String[] args) 8. { 9. String s ; 10. Random rand new Random(); 11. for (int i 0; i 10; i) 12. { 13. s s rand.nextInt(1000) ; 14. } 15. System.out.println(s); 16. } 17. } 上面的代码返编译后的Java Byte Code如下 1. package string; 2. 3. import java.io.PrintStream; 4. import java.util.Random; 5. 6. public class TestComplexPlus 7. { 8. 9. public TestComplexPlus() 10. { 11. // 0 0:aload_0 12. // 1 1:invokespecial #8 Method void Object() 13. // 2 4:return 14. } 15. 16. public static void main(String args[]) 17. { 18. String s ; 19. // 0 0:ldc1 #16 String 20. // 1 2:astore_1 21. Random rand new Random(); 22. // 2 3:new #18 Class Random 23. // 3 6:dup 24. // 4 7:invokespecial #20 Method void Random() 25. // 5 10:astore_2 26. for(int i 0; i 10; i) 27. //* 6 11:iconst_0 28. //* 7 12:istore_3 29. //* 8 13:goto 49 30. s (new StringBuilder(String.valueOf(s))).append(rand.nextInt(1000)).append( ).t oString(); 31. // 9 16:new #21 Class StringBuilder 32. // 10 19:dup 33. // 11 20:aload_1 34. // 12 21:invokestatic #23 Method String String.valueOf(Object) 35. // 13 24:invokespecial #29 Method void StringBuilder(String) 36. // 14 27:aload_2 37. // 15 28:sipush 1000 38. // 16 31:invokevirtual #32 Method int Random.nextInt(int) 39. // 17 34:invokevirtual #36 Method StringBuilder StringBuilder.append(int) 40. // 18 37:ldc1 #40 String 41. // 19 39:invokevirtual #42 Method StringBuilder StringBuilder.append(String) 42. // 20 42:invokevirtual #45 Method String StringBuilder.toString() 43. // 21 45:astore_1 44. 45. // 22 46:iinc 3 1 46. // 23 49:iload_3 47. // 24 50:bipush 10 48. // 25 52:icmplt 16 49. System.out.println(s); 50. // 26 55:getstatic #49 Field PrintStream System.out 51. // 27 58:aload_1 52. // 28 59:invokevirtual #55 Method void PrintStream.println(String) 53. // 29 62:return 54. } 55. } 大家可以看到虽然编译器将转换成了StringBuilder但创建StringBuilder对象的位置却在for语句内 部。这就意味着每执行一次循环就会创建一个StringBuilder对象对于本例来说是创建了10个StringBuilder 对象虽然Java有垃圾回收器但这个回收器的工作时间是不定的。如果不断产生这样的垃圾那么仍然会占用 大量的资源。解决这个问题的方法就是在程序中直接使用StringBuilder来连接字符串代码如下 1. package string; 2. 3. import java.util.*; 4. 5. public class TestStringBuilder 6. { 7. public static void main(String[] args) 8. { 9. String s ; 10. Random rand new Random(); 11. StringBuilder result new StringBuilder(); 12. for (int i 0; i 10; i) 13. { 14. result.append(rand.nextInt(1000)); 15. result.append( ); 16. } 17. System.out.println(result.toString()); 18. } 19. } 上面代码反编译后的结果如下 1. 20.package string; 2. 3. import java.io.PrintStream; 4. import java.util.Random; 5. 6. public class TestStringBuilder 7. { 8. 9. public TestStringBuilder() 10. { 11. // 0 0:aload_0 12. // 1 1:invokespecial #8 Method void Object() 13. // 2 4:return 14. } 15. 16. public static void main(String args[]) 17. { 18. String s ; 19. // 0 0:ldc1 #16 String 20. // 1 2:astore_1 21. Random rand new Random(); 22. // 2 3:new #18 Class Random 23. // 3 6:dup 24. // 4 7:invokespecial #20 Method void Random() 25. // 5 10:astore_2 26. StringBuilder result new StringBuilder(); 27. // 6 11:new #21 Class StringBuilder 28. // 7 14:dup 29. // 8 15:invokespecial #23 Method void StringBuilder() 30. // 9 18:astore_3 31. for(int i 0; i 10; i) 32. //* 10 19:iconst_0 33. //* 11 20:istore 4 34. //* 12 22:goto 47 35. { 36. result.append(rand.nextInt(1000)); 37. // 13 25:aload_3 38. // 14 26:aload_2 39. // 15 27:sipush 1000 40. // 16 30:invokevirtual #24 Method int Random.nextInt(int) 41. // 17 33:invokevirtual #28 Method StringBuilder StringBuilder.append(int) 42. // 18 36:pop 43. result.append( ); 44. // 19 37:aload_3 45. // 20 38:ldc1 #32 String 46. // 21 40:invokevirtual #34 Method StringBuilder StringBuilder.append(String) 47. // 22 43:pop 48. } 49. 50. // 23 44:iinc 4 1 51. // 24 47:iload 4 52. // 25 49:bipush 10 53. // 26 51:icmplt 25 54. System.out.println(result.toString()); 55. // 27 54:getstatic #37 Field PrintStream System.out 56. // 28 57:aload_3 57. // 29 58:invokevirtual #43 Method String StringBuilder.toString() 58. // 30 61:invokevirtual #47 Method void PrintStream.println(String) 59. // 31 64:return 60. } 61. } 从上面的反编译结果可以看出创建StringBuilder的代码被放在了for语句外。虽然这样处理在源程序中看起 来复杂但却换来了更高的效率同时消耗的资源也更少了。 在使用StringBuilder时要注意尽量不要和StringBuilder混着用否则会创建更多的StringBuilder对 象如下面代码所 for (int i 0; i 10; i) { result.append(rand.nextInt(1000)); result.append( ); } 改成如下形式 for (int i 0; i 10; i { result.append(rand.nextInt(1000) ); } 则反编译后的结果如下 for(int i 0; i 10; i) //* 10 19:iconst_0 //* 11 20:istore 4 //* 12 22:goto 65 { result.append((new StringBuilder(String.valueOf(rand.nextInt(1000)))).append( ).toString()); // 13 25:aload_3 // 14 26:new #21 Class StringBuilder // 15 29:dup 从上面的代码可以看出Java编译器将编译成了StringBuilder这样for语句每循环一次又创建了一个 StringBuilder对象。 如果将上面的代码在JDK1.4下编译必须将StringBuilder改为StringBuffer而JDK1.4将转换为 StringBuffer因为JDK1.4并没有提供StringBuilder类。StringBuffer和StringBuilder的功能基本一样只是 StringBuffer是线程安全的而StringBuilder不是线程安全的。因此StringBuilder的效率会更高。 6. 请说出下面程序的输出 1. class StringEqualTest { 2. public static void main(String[] args) { 3. String s1 Programming; 4. String s2 new String(Programming); 5. String s3 Program; 6. String s4 ming; 7. String s5 Program ming; 8. String s6 s3 s4; 9. System.out.println(s1 s2); //false 10. System.out.println(s1 s5); //true 11. System.out.println(s1 s6); //false 12. System.out.println(s1 s6.intern()); //true 13. System.out.println(s2 s2.intern()); //false 14. } 15. } 补充解答上面的面试题需要知道如下两个知识点 1. String对象的intern方法会得到字符串对象在常量池中对应的版本的引用如果常量池中有一个字符串与 String 对象的 equals结果是 true如果常量池中没有对应的字符串则该字符串将被添加到常量池中然后返 回常量池中字符串的引用 2. 字符串的操作其本质是创建了StringBuilder 对象进行 append 操作然后将拼接后的 StringBuilder 对 象用 toString 方法处理成 String 对象这一点可以用 javap -c StringEqualTest.class 命令获得 class 文件对应 的 JVM 字节码指令就可以看出来。 7. Java中的日期和时间 7.1如何取得年月日、小时分钟秒 1. public class DateTimeTest { 2. public static void main(String[] args) { 3. Calendar cal Calendar.getInstance(); 4. System.out.println(cal.get(Calendar.YEAR)); 5. System.out.println(cal.get(Calendar.MONTH)); // 0 - 11 6. System.out.println(cal.get(Calendar.DATE)); 7. System.out.println(cal.get(Calendar.HOUR_OF_DAY)); 8. System.out.println(cal.get(Calendar.MINUTE)); 9. System.out.println(cal.get(Calendar.SECOND)); 10. // Java 8 11. LocalDateTime dt LocalDateTime.now(); 12. System.out.println(dt.getYear()); 13. System.out.println(dt.getMonthValue()); // 1 - 12 14. System.out.println(dt.getDayOfMonth()); 15. System.out.println(dt.getHour()); 16. System.out.println(dt.getMinute()); 17. System.out.println(dt.getSecond()); 18. } 19. } 7.2如何取得从1970年1月1日0时0分0 秒到现在的毫秒数 1. Calendar.getInstance().getTimeInMillis(); //第一种方式 2. System.currentTimeMillis(); //第二种方式 3. // Java 8 4. Clock.systemDefaultZone().millis(); 7.3如何取得某月的最后一天 1. //获取当前月第一天 2. Calendar c Calendar.getInstance(); 3. c.add(Calendar.MONTH, 0); 4. c.set(Calendar.DAY_OF_MONTH,1);//设置为1号,当前日期既为本月第一天 5. String first format.format(c.getTime()); 6. System.out.println(first:first); 7. 8. //获取当前月最后一天 9. Calendar ca Calendar.getInstance(); 10. ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH)); 11. String last format.format(ca.getTime()); 12. System.out.println(last:last); 13. 14. //Java 8 15. LocalDate today LocalDate.now(); 16. //本月的第一天 17. LocalDate firstday LocalDate.of(today.getYear(),today.getMonth(),1); 18. //本月的最后一天 19. LocalDate lastDay today.with(TemporalAdjusters.lastDayOfMonth()); 20. System.out.println(本月的第一天firstday); 21. System.out.println(本月的最后一天lastDay); 7.4如何格式化日期 1Java.text.DataFormat 的子类如 SimpleDateFormat 类中的 format(Date)方法可将日期格式化。 2Java 8 中可以用 java.time.format.DateTimeFormatter来格式化时间日期代码如下所示 1. import java.text.SimpleDateFormat; 2. import java.time.LocalDate; 3. import java.time.format.DateTimeFormatter; 4. import java.util.Date; 5. class DateFormatTest { 6. 7. public static void main(String[] args) { 8. SimpleDateFormat oldFormatter new SimpleDateFormat(yyyy/MM/dd); 9. Date date1 new Date(); 10. System.out.println(oldFormatter.format(date1)); 11. 12. // Java 8 13. DateTimeFormatter newFormatter DateTimeFormatter.ofPattern(yyyy/MM/dd); 14. LocalDate date2 LocalDate.now(); 15. System.out.println(date2.format(newFormatter)); 16. } 17. } 补充Java的时间日期API一直以来都是被诟病的东西为了解决这一问题Java 8中引入了新的时间日期API 其中包括 LocalDate、LocalTime、LocalDateTime、Clock、Instant 等类这些的类的设计都使用了不变模式因 此是线程安全的设计。 7.5打印昨天的当前时刻 1. import java.util.Calendar; 2. class YesterdayCurrent { 3. public static void main(String[] args){ 4. Calendar cal Calendar.getInstance(); 5. cal.add(Calendar.DATE, -1); 6. System.out.println(cal.getTime()); 7. } 8. } 9. 10. 11. //java-8 12. import java.time.LocalDateTime; 13. class YesterdayCurrent { 14. public static void main(String[] args) { 15. LocalDateTime today LocalDateTime.now(); 16. LocalDateTime yesterday today.minusDays(1); 17. System.out.println(yesterday); 18. } 19. } 7.6 Java8的日期特性 Java 8日期/时间特性 Java 8日期/时间API是JSR-310的实现它的实现目标是克服旧的日期时间实现中所有的缺陷新的日期/时间 API的一些设计原则是 l 不变性新的日期/时间API中所有的类都是不可变的这对多线程环境有好处。 l 关注点分离新的API将人可读的日期时间和机器时间unix timestamp明确分离它为日期Date、时间 Time、日期时间DateTime、时间戳unix timestamp以及时区定义了不同的类。 l 清晰在所有的类中方法都被明确定义用以完成相同的行为。举个例子要拿到当前实例我们可以使用now()方 法在所有的类中都定义了format()和parse()方法而不是像以前那样专门有一个独立的类。为了更好的处理问 题所有的类都使用了工厂模式和策略模式一旦你使用了其中某个类的方法与其他类协同工作并不困难。 l 实用操作所有新的日期/时间API类都实现了一系列方法用以完成通用的任务如加、减、格式化、解析、从 日期/时间中提取单独部分等等。 l 可扩展性新的日期/时间API是工作在ISO-8601日历系统上的但我们也可以将其应用在非ISO的日历上。 Java 8日期/时间API包解释 l java.time包这是新的Java日期/时间API的基础包所有的主要基础类都是这个包的一部分如LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的在绝大多 数情况下这些类能够有效地处理一些公共的需求。 l java.time.chrono 包这个包为非 ISO 的日历系统定义了一些泛化的 API我们可以扩展 AbstractChronology 类来创建自己的日历系统。 l java.time.format 包这个包包含能够格式化和解析日期时间对象的类在绝大多数情况下我们不应该直接使 用它们因为java.time包中相应的类已经提供了格式化和解析的方法。 l java.time.temporal包这个包包含一些时态对象我们可以用其找出关于日期/时间对象的某个特定日期或时间 比如说可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法因为它们都具有“withXXX”的格 式。 l java.time.zone包这个包包含支持不同时区以及相关规则的类。 Java 8日期/时间常用API 1.java.time.LocalDate LocalDate是一个不可变的类它表示默认格式(yyyy-MM-dd)的日期我们可以使用now()方法得到当前时间也可以提供输入年份、月份和日期的输入参数来创建一个 LocalDate实例。该类为 now()方法提供了重载方法我们可以传入ZoneId来获得指定时区的日期。该类提供与java.sql.Date相同的功能对于如何使用该类我们来看一个简单的例子。 package com.journaldev.java8.time; import java.time.LocalDate; import java.time.Month; import java.time.ZoneId; /** * LocalDate Examples * author pankaj * */ public class LocalDateExample { public static void main(String[] args) { //Current Date LocalDate today LocalDate.now(); System.out.println(Current Datetoday); //Creating LocalDate by providing input arguments LocalDate firstDay_2014 LocalDate.of(2014, Month.JANUARY, 1); System.out.println(Specific DatefirstDay_2014); //Try creating date by providing invalid inputs //LocalDate feb29_2014 LocalDate.of(2014, Month.FEBRUARY, 29); //Exception in thread main java.time.DateTimeException: //Invalid date February 29 as 2014 is not a leap year //Current date in Asia/Kolkata, you can get it from ZoneId javadoc LocalDate todayKolkata LocalDate.now(ZoneId.of(Asia/Kolkata)); System.out.println(Current Date in ISTtodayKolkata); //java.time.zone.ZoneRulesException: Unknown time-zone ID: IST //LocalDate todayIST LocalDate.now(ZoneId.of(IST)); //Getting date from the base date i.e 01/01/1970 LocalDate dateFromBase LocalDate.ofEpochDay(365); System.out.println(365th day from base date dateFromBase); LocalDate hundredDay2014 LocalDate.ofYearDay(2014, 100); System.out.println(100th day of 2014hundredDay2014); } } 输出 Current Date2014-04-28 Specific Date2014-01-01 Current Date in IST2014-04-29 365th day from base date 1971-01-01 100th day of 20142014-04-10 2.java.time.LocalTime LocalTime 是一个不可变的类它的实例代表一个符合人类可读格式的时间默认格式是 hh:mm:ss.zzz。像LocalDate一样该类也提供了时区支持同时也可以传入小时、分钟和秒等输入参数创建实例我们来看一个简单的程序演示该类的使用方法。 package com.journaldev.java8.time; import java.time.LocalTime; import java.time.ZoneId; /** * LocalTime Examples */ public class LocalTimeExample { public static void main(String[] args) { //Current Time LocalTime time LocalTime.now(); System.out.println(Current Timetime); //Creating LocalTime by providing input arguments LocalTime specificTime LocalTime.of(12,20,25,40); System.out.println(Specific Time of DayspecificTime); //Try creating time by providing invalid inputs //LocalTime invalidTime LocalTime.of(25,20); //Exception in thread main java.time.DateTimeException: //Invalid value for HourOfDay (valid values 0 - 23): 25 //Current date in Asia/Kolkata, you can get it from ZoneId javadoc LocalTime timeKolkata LocalTime.now(ZoneId.of(Asia/Kolkata)); System.out.println(Current Time in ISTtimeKolkata); //java.time.zone.ZoneRulesException: Unknown time-zone ID: IST //LocalTime todayIST LocalTime.now(ZoneId.of(IST)); //Getting date from the base date i.e 01/01/1970 LocalTime specificSecondTime LocalTime.ofSecondOfDay(10000); System.out.println(10000th second time specificSecondTime); } } 输出 Current Time15:51:45.240 Specific Time of Day12:20:25.000000040 Current Time in IST04:21:45.276 10000th second time 02:46:40 3. java.time.LocalDateTime LocalDateTime 是一个不可变的日期-时间对象它表示一组日期-时间默认格式是 yyyy-MM-dd-HH-mm- ss.zzz。它提供了一个工厂方法接收LocalDate和LocalTime输入参数创建LocalDateTime实例。我们来看一个 简单的例子。 package com.journaldev.java8.time; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.ZoneId; import java.time.ZoneOffset; public class LocalDateTimeExample { public static void main(String[] args) { //Current Date LocalDateTime today LocalDateTime.now(); System.out.println(Current DateTimetoday); //Current Date using LocalDate and LocalTime today LocalDateTime.of(LocalDate.now(), LocalTime.now()); System.out.println(Current DateTimetoday); //Creating LocalDateTime by providing input arguments LocalDateTime specificDate LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30); System.out.println(Specific DatespecificDate); //Try creating date by providing invalid inputs //LocalDateTime feb29_2014 LocalDateTime.of(2014, Month.FEBRUARY, 28, 25,1,1); //Exception in thread main java.time.DateTimeException: //Invalid value for HourOfDay (valid values 0 - 23): 25 //Current date in Asia/Kolkata, you can get it from ZoneId javadoc LocalDateTime todayKolkata LocalDateTime.now(ZoneId.of(Asia/Kolkata)); System.out.println(Current Date in ISTtodayKolkata); //java.time.zone.ZoneRulesException: Unknown time-zone ID: IST //LocalDateTime todayIST LocalDateTime.now(ZoneId.of(IST)); //Getting date from the base date i.e 01/01/1970 LocalDateTime dateFromBase LocalDateTime.ofEpochSecond(10000, 0, ZoneOffset.UTC); System.out.println(10000th second time from 01/01/1970 dateFromBase); } } 输出 Current DateTime2014-04-28T16:00:49.455 Current DateTime2014-04-28T16:00:49.493 Specific Date2014-01-01T10:10:30 Current Date in IST2014-04-29T04:30:49.493 10000th second time from 01/01/1970 1970-01-01T02:46:40 在所有这三个例子中我们已经看到如果我们提供了无效的参数去创建日期/时间那么系统会抛出 java.time.DateTimeException这是一种运行时异常我们并不需要显式地捕获它。 同时我们也看到能够通过传入ZoneId得到日期/时间数据你可以从它的Javadoc中得到支持的Zoneid的列 表当运行以上类时可以得到以上输出。 4. java.time.Instant Instant类是用在机器可读的时间格式上的它以Unix时间戳的形式存储日期时间我们来看一个简单的程序 package com.journaldev.java8.time; import java.time.Duration; import java.time.Instant; public class InstantExample { public static void main(String[] args) { //Current timestamp Instant timestamp Instant.now(); System.out.println(Current Timestamp timestamp); //Instant from timestamp Instant specificTime Instant.ofEpochMilli(timestamp.toEpochMilli()); System.out.println(Specific Time specificTime); //Duration example Duration thirtyDay Duration.ofDays(30); System.out.println(thirtyDay); } } 输出 Current Timestamp 2014-04-28T23:20:08.489Z Specific Time 2014-04-28T23:20:08.489Z PT720H 5. 日期API工具 我们早些时候提到过大多数日期/时间API类都实现了一系列工具方法如加/减天数、周数、月份数等等。 还有其他的工具方法能够使用TemporalAdjuster调整日期并计算两个日期间的周期。 package com.journaldev.java8.time; import java.time.LocalDate; import java.time.LocalTime; import java.time.Period; import java.time.temporal.TemporalAdjusters; public class DateAPIUtilities { public static void main(String[] args) { LocalDate today LocalDate.now(); //Get the Year, check if its leap year System.out.println(Year today.getYear() is Leap Year? today.isLeapYear()); //Compare two LocalDate for before and after System.out.println(Today is before 01/01/2015? today.isBefore(LocalDate.of(2015,1,1))); //Create LocalDateTime from LocalDate System.out.println(Current Timetoday.atTime(LocalTime.now())); //plus and minus operations System.out.println(10 days after today will be today.plusDays(10)); System.out.println(3 weeks after today will be today.plusWeeks(3)); System.out.println(20 months after today will be today.plusMonths(20)); System.out.println(10 days before today will be today.minusDays(10)); System.out.println(3 weeks before today will be today.minusWeeks(3)); System.out.println(20 months before today will be today.minusMonths(20)); //Temporal adjusters for adjusting the dates System.out.println(First date of this month today. with(TemporalAdjusters.firstDayOfMonth())); LocalDate lastDayOfYear today.with(TemporalAdjusters.lastDayOfYear()); System.out.println(Last date of this year lastDayOfYear); Period period today.until(lastDayOfYear); System.out.println(Period Format period); System.out.println(Months remaining in the year period.getMonths()); } } 输出 Year 2014 is Leap Year? false Today is before 01/01/2015? true Current Time2014-04-28T16:23:53.154 10 days after today will be 2014-05-08 3 weeks after today will be 2014-05-19 20 months after today will be 2015-12-28 10 days before today will be 2014-04-18 3 weeks before today will be 2014-04-07 20 months before today will be 2012-08-28 First date of this month 2014-04-01 Last date of this year 2014-12-31 Period Format P8M3D Months remaining in the year 8 6. 解析和格式化 将一个日期格式转换为不同的格式之后再解析一个字符串得到日期时间对象这些都是很常见的。我们来看一 下简单的例子。 package com.journaldev.java8.time; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class DateParseFormatExample { public static void main(String[] args) { //Format examples LocalDate date LocalDate.now(); //default format System.out.println(Default format of LocalDatedate); //specific format System.out.println(date.format(DateTimeFormatter.ofPattern(d::MMM::uuuu))); System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE)); LocalDateTime dateTime LocalDateTime.now(); //default format System.out.println(Default format of LocalDateTimedateTime); //specific format System.out.println(dateTime.format(DateTimeFormatter.ofPattern(d::MMM::uuuu HH::mm::ss))); System.out.println(dateTime.format(DateTimeFormatter.BASIC_ISO_DATE)); Instant timestamp Instant.now(); //default format System.out.println(Default format of Instanttimestamp); //Parse examples LocalDateTime dt LocalDateTime.parse(27::Apr::2014 21::39::48, DateTimeFormatter.ofPattern(d::MMM::uuuu HH::mm::ss)); System.out.println(Default format after parsing dt); } } 输出 Default format of LocalDate2014-04-28 28::Apr::2014 20140428 Default format of LocalDateTime2014-04-28T16:25:49.341 28::Apr::2014 16::25::49 20140428 Default format of Instant2014-04-28T23:25:49.342Z Default format after parsing 2014-04-27T21:39:48 7. 旧的日期时间支持 旧的日期/时间类已经在几乎所有的应用程序中使用因此做到向下兼容是必须的。这也是为什么会有若干工具方 法帮助我们将旧的类转换为新的类反之亦然。我们来看一下简单的例子。 package com.journaldev.java8.time; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; public class DateAPILegacySupport { public static void main(String[] args) { //Date to Instant Instant timestamp new Date().toInstant(); //Now we can convert Instant to LocalDateTime or other similar classes LocalDateTime date LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get(PST))); System.out.println(Date date); //Calendar to Instant Instant time Calendar.getInstance().toInstant(); System.out.println(time); //TimeZone to ZoneId ZoneId defaultZone TimeZone.getDefault().toZoneId(); System.out.println(defaultZone); //ZonedDateTime from specific Calendar ZonedDateTime gregorianCalendarDateTime new GregorianCalendar().toZonedDateTime(); System.out.println(gregorianCalendarDateTime); //Date API to Legacy classes Date dt Date.from(Instant.now()); System.out.println(dt); TimeZone tz TimeZone.getTimeZone(defaultZone); System.out.println(tz); GregorianCalendar gc GregorianCalendar.from(gregorianCalendarDateTime); System.out.println(gc); } } 输出 Date 2014-04-28T16:28:54.340 2014-04-28T23:28:54.395Z America/Los_Angeles 2014-04-28T16:28:54.404-07:00[America/Los_Angeles] Mon Apr 28 16:28:54 PDT 2014 sun.util.calendar.ZoneInfo[idAmerica/Los_Angeles,offset-28800000,dstSavings3600000,useDaylighttrue,transitions185,lastRulejava.util.SimpleTimeZone[idA merica/Los_Angeles,offset-28800000,dstSavings3600000,useDaylighttrue,startYear0,startMode3,startMonth2,startDay8,startD ayOfWeek1,startTime7200000,startTimeMode0,endMode3,endMonth10,endDay1,endDayOfWeek1,endTime 7200000,endTimeMode0]] java.util.GregorianCalendar[time1398727734404,areFieldsSettrue,areAllFieldsSettrue,lenientt rue,zonesun.util.calendar.ZoneInfo[idAmerica/Los_Angeles,offset-28800000,dstSavings3600000,useDaylighttrue,transitions185,lastRulejava.util.SimpleTimeZone[idA merica/Los_Angeles,offset-28800000,dstSavings3600000,useDaylighttrue,startYear0,startMode3,startMonth2,startDay8,startD ayOfWeek1,startTime7200000,startTimeMode0,endMode3,endMonth10,endDay1,endDayOfWeek1,endTime 7200000,endTimeMode0]],firstDayOfWeek2,minimalDaysInFirstWeek4,ERA1,YEAR2014,MONTH3,WEEK_OF_Y EAR18,WEEK_OF_MONTH5,DAY_OF_MONTH28,DAY_OF_YEAR118,DAY_OF_WEEK2,DAY_OF_WEEK_IN_MONTH4,AM_PM1 ,HOUR4,HOUR_OF_DAY16,MINUTE28,SECOND54,MILLISECOND404,ZONE_OFFSET-28800000,DST_OFFSET3600000] 补充我们可以看到旧的TimeZone和GregorianCalendar类的toString()方法太啰嗦了一点都不友好。 7.7 Java8之前的日期和时间使用的槽点 Tiago Fernandez 做过一次投票选举最烂的 JAVA API排第一的 EJB2.X第二的就是日期 APIDate 和Calender 1. 槽点一 最开始的时候Date 既要承载日期信息又要做日期之间的转换还要做不同日期格式的显示职责较繁杂不懂单一职责你妈妈知道吗纯属恶搞~哈哈 后来从 JDK 1.1 开始这三项职责分开了 1使用 Calendar 类实现日期和时间字段之间转换 2使用 DateFormat 类来格式化和分析日期字符串 3而 Date 只用来承载日期和时间信息。 原有 Date 中的相应方法已废弃。不过无论是 Date还是 Calendar都用着太不方便了这是 API 没有设计好的地方。 2. 槽点二 坑爹的 year 和 month。 我们看下面的代码 1. Date date new Date(2012,1,1); 2. System.out.println(date); 输出 Thu Feb 01 00:00:00 CST 3912 观察输出结果year 是 20121900而 month月份参数我不是给了 1 吗怎么输出二月Feb了 应该曾有人告诉你如果你要设置日期应该使用 java.util.Calendar像这样... 1. Calendar calendar Calendar.getInstance(); 2. calendar.set(2013, 8, 2); 这样写又不对了calendar 的 month 也是从 0 开始的表达 8 月份应该用 7 这个数字要么就干脆用枚举 1. calendar.set(2013, Calendar.AUGUST, 2); 注意上面的代码Calendar 年份的传值不需要减去 1900当然月份的定义和 Date 还是一样这种不一致真 是让人抓狂有些人可能知道Calendar 相关的 API 是 IBM 捐出去的所以才导致不一致。 3. 槽点三 java.util.Date 与 java.util.Calendar 中的所有属性都是可变的 下面的代码计算两个日期之间的天数.... 1. public static void main(String[] args) { 2. Calendar birth Calendar.getInstance(); 3. birth.set(1975, Calendar.MAY, 26); 4. Calendar now Calendar.getInstance(); 5. System.out.println(daysBetween(birth, now)); 6. System.out.println(daysBetween(birth, now)); // 显示 0 7. } 8. 9. public static long daysBetween(Calendar begin, Calendar end) { 10. long daysBetween 0; 11. while(begin.before(end)) { 12. begin.add(Calendar.DAY_OF_MONTH, 1); 13. daysBetween; 14. } 15. return daysBetween; 16. } daysBetween 有点问题如果连续计算两个 Date 实例的话第二次会取得 0因为 Calendar 状态是可变的考 虑到重复计算的场合最好复制一个新的 Calendar 1. public static long daysBetween(Calendar begin, Calendar end) { 2. Calendar calendar (Calendar) begin.clone(); // 复制 3. long daysBetween 0; 4. while(calendar.before(end)) { 5. calendar.add(Calendar.DAY_OF_MONTH, 1); 6. daysBetween; 7. } 8. return daysBetween; 9. } 以上种种导致目前有些第三方的 java 日期库诞生比如广泛使用的 JODA-TIME还有 Date4j 等虽然第三方库已经足3 / 8够强大好用但还是有兼容问题的比如标准的 JSF 日期转换器与 joda-time API 就不兼容你需要编写自己的转换器所以标准的 API 还是必须的于是就有了 JSR310。 7.8 Java8日期实现JSR310规范 1. JSR310介绍 JSR 310 实际上有两个日期概念。第一个是 Instant它大致对应于 java.util.Date 类因为它代表了一个确定的时间点即相对于标准 Java 纪元1970 年 1 月 1 日的偏移量但与 java.util.Date 类不同的是其精确到了纳秒级别。 第二个对应于人类自身的观念比如 LocalDate 和 LocalTime。他们代表了一般的时区概念要么是日期不包含时间要么是时间不包含日期类似于 java.sql 的表示方式。此外还有一个 MonthDay它可以存储某人的生日不包含年份。每个类都在内部存储正确的数据而不是像 java.util.Date 那样利用午夜 12 点来区分日期利用 1970-01-01 来表示时间。 目前 Java8 已经实现了 JSR310 的全部内容。新增了 java.time 包定义的类表示了日期-时间概念的规则包括 instants,durations, dates, times, time-zones and periods。这些都是基于 ISO 日历系统它又是遵循 Gregorian 规则的。最重要的一点是值不可变且线程安全通过下面一张图我们快速看下 java.time 包下的一些主要的类的值的格式方便理解。 2. Java8方法概览 java.time包下的方法概览 方法名 说明 Of 静态工厂方法 parse 静态工厂方法关注于解析 get 获取某些东西的值 is 检查某些东西的是否是 true with 不可变的 setter 等价物 plus 加一些量到某个对象 minus 从某个对象减去一些量 to 转换到另一个类型 at 把这个对象与另一个对象组合起来 与旧的API相比 3. 简单实用java.time的API实用 1. public class TimeIntroduction { 2. public static void testClock() throws InterruptedException { 3. //时钟提供给我们用于访问某个特定 时区的 瞬时时间、日期 和 时间的。 4. Clock c1 Clock.systemUTC(); //系统默认 UTC 时钟当前瞬时时间 System.currentTimeMillis() 5. System.out.println(c1.millis()); //每次调用将返回当前瞬时时间UTC 6. Clock c2 Clock.systemDefaultZone(); //系统默认时区时钟当前瞬时时间 7. Clock c31 Clock.system(ZoneId.of(Europe/Paris)); //巴黎时区 8. System.out.println(c31.millis()); //每次调用将返回当前瞬时时间UTC 9. Clock c32 Clock.system(ZoneId.of(Asia/Shanghai));//上海时区 10. System.out.println(c32.millis());//每次调用将返回当前瞬时时间UTC 11. Clock c4 Clock.fixed(Instant.now(), ZoneId.of(Asia/Shanghai));//固定上海时区时钟 12. System.out.println(c4.millis()); 13. Thread.sleep(1000); 14. 15. System.out.println(c4.millis()); //不变 即时钟时钟在那一个点不动 16. Clock c5 Clock.offset(c1, Duration.ofSeconds(2)); //相对于系统默认时钟两秒的时钟 17. System.out.println(c1.millis()); 18. System.out.println(c5.millis()); 19. } 20. public static void testInstant() { 21. //瞬时时间 相当于以前的 System.currentTimeMillis() 22. Instant instant1 Instant.now(); 23. System.out.println(instant1.getEpochSecond());//精确到秒 得到相对于 1970-01-01 00:00:00 24. UTC 的一个时间 25. System.out.println(instant1.toEpochMilli()); //精确到毫秒 26. Clock clock1 Clock.systemUTC(); //获取系统 UTC 默认时钟 27. Instant instant2 Instant.now(clock1);//得到时钟的瞬时时间 28. System.out.println(instant2.toEpochMilli()); 29. Clock clock2 Clock.fixed(instant1, ZoneId.systemDefault()); //固定瞬时时间时钟 30. Instant instant3 Instant.now(clock2);//得到时钟的瞬时时间 31. System.out.println(instant3.toEpochMilli());//equals instant1 32. } 33. public static void testLocalDateTime() { 34. //使用默认时区时钟瞬时时间创建 Clock.systemDefaultZone() --即相对于 ZoneId.systemDefault() 35. 默认时区 36. LocalDateTime now LocalDateTime.now(); 37. System.out.println(now); 38. //自定义时区 39. LocalDateTime now2 LocalDateTime.now(ZoneId.of(Europe/Paris)); 40. System.out.println(now2);//会以相应的时区显示日期 41. //自定义时钟 42. Clock clock Clock.system(ZoneId.of(Asia/Dhaka)); 43. LocalDateTime now3 LocalDateTime.now(clock); 44. System.out.println(now3);//会以相应的时区显示日期 45. //不需要写什么相对时间 如 java.util.Date 年是相对于 1900 月是从 0 开始 46. //2013-12-31 23:59 47. LocalDateTime d1 LocalDateTime.of(2013, 12, 31, 23, 59); 48. //年月日 时分秒 纳秒 49. LocalDateTime d2 LocalDateTime.of(2013, 12, 31, 23, 59, 59, 11); 50. //使用瞬时时间 时区 51. Instant instant Instant.now(); 52. LocalDateTime d3 LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()); 53. System.out.println(d3); 54. //解析 String---LocalDateTime 55. LocalDateTime d4 LocalDateTime.parse(2013-12-31T23:59); 56. System.out.println(d4); 57. LocalDateTime d5 LocalDateTime.parse(2013-12-31T23:59:59.999);//999 毫秒 等价于 58. 999000000 纳秒 59. 60. System.out.println(d5); 61. //使用 DateTimeFormatter API 解析 和 格式化 62. DateTimeFormatter formatter DateTimeFormatter.ofPattern(yyyy/MM/dd HH:mm:ss); 63. LocalDateTime d6 LocalDateTime.parse(2013/12/31 23:59:59, formatter); 64. System.out.println(formatter.format(d6)); 65. //时间获取 66. System.out.println(d6.getYear()); 67. System.out.println(d6.getMonth()); 68. System.out.println(d6.getDayOfYear()); 69. System.out.println(d6.getDayOfMonth()); 70. System.out.println(d6.getDayOfWeek()); 71. System.out.println(d6.getHour()); 72. System.out.println(d6.getMinute()); 73. System.out.println(d6.getSecond()); 74. System.out.println(d6.getNano()); 75. //时间增减 76. LocalDateTime d7 d6.minusDays(1); 77. LocalDateTime d8 d7.plus(1, IsoFields.QUARTER_YEARS); 78. //LocalDate 即年月日 无时分秒 79. //LocalTime 即时分秒 无年月日 80. //API 和 LocalDateTime 类似就不演示了 81. } 82. public static void testZonedDateTime() { 83. //即带有时区的 date-time 存储纳秒、时区和时差避免与本地 date-time 歧义。 84. //API 和 LocalDateTime 类似只是多了时差(如 2013-12-20T10:35:50.71108:00[Asia/Shanghai]) 85. ZonedDateTime now ZonedDateTime.now(); 86. System.out.println(now); 87. ZonedDateTime now2 ZonedDateTime.now(ZoneId.of(Europe/Paris)); 88. System.out.println(now2); 89. //其他的用法也是类似的 就不介绍了 90. ZonedDateTime z1 ZonedDateTime.parse(2013-12-31T23:59:59Z[Europe/Paris]); 91. System.out.println(z1); 92. } 93. public static void testDuration() { 94. //表示两个瞬时时间的时间段 95. Duration d1 Duration.between(Instant.ofEpochMilli(System.currentTimeMillis() - 12323123), 96. Instant.now()) 97. ; 98. //得到相应的时差 99. System.out.println(d1.toDays()); 100. System.out.println(d1.toHours()); 101. System.out.println(d1.toMinutes()); 102. 103. System.out.println(d1.toMillis()); 104. System.out.println(d1.toNanos()); 105. //1 天时差 类似的还有如 ofHours() 106. Duration d2 Duration.ofDays(1); 107. System.out.println(d2.toDays()); 108. } 109. public static void testChronology() { 110. //提供对 java.util.Calendar 的替换提供对年历系统的支持 111. Chronology c HijrahChronology.INSTANCE; 112. ChronoLocalDateTime d c.localDateTime(LocalDateTime.now()); 113. System.out.println(d); 114. } 115. /** 116. * 新旧日期转换 117. */ 118. public static void testNewOldDateConversion(){ 119. Instant instantnew Date().toInstant(); 120. Date dateDate.from(instant); 121. System.out.println(instant); 122. System.out.println(date); 123. } 124. public static void main(String[] args) throws InterruptedException { 125. testClock(); 126. testInstant(); 127. testLocalDateTime(); 128. testZonedDateTime(); 129. testDuration(); 130. testChronology(); 131. testNewOldDateConversion(); 132. } 133. } 7.9 JSR310规范Joda-Time的区别 其实 JSR310 的规范领导者 Stephen Colebourne同时也是 Joda-Time 的创建者JSR310 是在 Joda- Time 的基础上建立的参考了绝大部分的 API但并不是说 JSR310JODA-Time下面几个比较明显的区别是 1. 最明显的变化就是包名从 org.joda.time 以及 java.time
2. JSR310 不接受 NULL 值Joda-Time 视 NULL 值为 0
3. JSR310 的计算机相关的时间Instant和与人类相关的时间DateTime之间的差别变得更明显
4. JSR310 所有抛出的异常都是 DateTimeException 的子类。虽然 DateTimeException 是一个
RuntimeException
7.10 总结 (2017-11-23-wl) Java.time java.util.Calendar 以及 Date 流畅的 API 不流畅的 API 实例不可变 实例可变 线程安全 非线程安全