jdk新特性
1.1 lambda表达式
一、处理匿名内部类
1、Runnable接口
1 new Thread(new Runnable() { 2 public void run() { 3 System.out.println("hello world!!!"); 4 } 5 }).start(); 6 7 // lambda 8 new Thread(()->System.out.println("hello lambda!!!")).start();
说明:
- 上边的方式是原本匿名内部类方式
- 下边的方法是lambda表达式方式
lambda基本语法:(形参列表)->{方法体}
注意:
- 形参列表:(String x, String y)这样的基本形式
- 如果没有形参,使用"()",如上
- 如果参数类型可以被推断出来,使用(x,y)
- 如果是单个参数且类型可以被推断出来,直接使用x
- 方法体:如果只有一句话,可以去掉"{}",如上
2、Comparator接口
1 List<String> strList = Arrays.asList("zhaojigang","nana","tianya"); 2 //原来的方式 3 Collections.sort(strList, new Comparator<String>() { 4 @Override 5 public int compare(String s1, String s2) { 6 return s1.compareTo(s2); 7 } 8 }); 9 10 //lambda 11 Collections.sort(strList, (s1, s2)->s1.compareTo(s2));
说明:这里的s1和s2就被根据comparator的泛型和strList的泛型推断出了类型为String,可以省略参数类型。
二、方法引用
1 //lambda 2 Collections.sort(strList, (s1, s2)->s1.compareTo(s2)); 3 //方法引用 4 Collections.sort(strList, String::compareTo); 5 //lambda 6 strList.forEach(x->System.out.println(x)); 7 //方法引用 8 strList.forEach(System.out::println);
说明:
- 前两个语句效果一样,后两个效果一样,自己比对方法引用与lambda的哪些部分等价
- 集合类的foreach方法就是增强型for循环的再增强。
注意:
- 方法引用的语法
- 对象::实例方法=>等价于"提供方法参数的lambda表达式"
- 类::静态方法=>等价于"提供方法参数的lambda表达式"
- eg. System.out::println等价于x->System.out.println(x)
- 类::实例方法=>第一个参数是执行方法的对象
- eg. String::compareTo等价于(s1, s2)->s1.compareTo(s2)
三、局部变量
lambda操作的局部变量必须是final型的,即:在lambda表达式所使用到的局部变量(方法体内的变量或形参)只能被读取,不能被改变。
注意:列出这条约束的原因是防止线程不安全,可能会有疑问,局部变量是方法私有的,怎么会有线程安全问题?
解释:假设我在该方法体内,启动了一个线程并使用lambda表达式去操作一个局部变量count(注意该变量并没有在lambda中进行声明,但是lambda却可以用,这就是"闭包"),而在该线程外且在该方法体内,该方法也操作了count,这时可能就会有线程安全问题了。
四、接口的改变
java的接口也可以写实现default级别的实例方法和静态方法了。
1 public interface LambdaInterface { 2 //default方法 3 default void defaultMethod(){ 4 System.out.println("xxxx"); 5 } 6 //static方法 7 static void staticMethod(){ 8 System.out.println("xxxx"); 9 } 10 }
1 public class TestInterface implements LambdaInterface{ 2 public static void main(String[] args) { 3 LambdaInterface test = new TestInterface(); 4 test.defaultMethod();//default方法测试 5 6 LambdaInterface.staticMethod();//static方法测试 7 } 8 }
用途:当改造老的项目时,想在旧的接口中添加一些方法,但是又不想让该接口的旧的实现类去实现这些方法时,可以使用这个技巧。
1.2 Stream API
引例:
1 List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana"); 2 Stream<String> streamList = strList.stream();//集合转为stream 3 strList = streamList.distinct().filter(str->!str.equals("tianya")).sorted(String::compareTo).collect(Collectors.toList()); 4 strList.forEach(System.out::println);
说明:
- 第一行:创建数组并转为List
- 第二行:根据List创建stream
- 第三行:对该stream进行去重-->选择-->排序-->stream转为List
- 第四行:遍历该List
以上代码显示了stream API的方便。当然,上边的代码可以更为简洁,如下改为一行:
Arrays.asList("zhaojigang","nana","tianya","nana").stream().distinct().filter(str->!str.equals("tianya")).sorted(String::compareTo).collect(Collectors.toList()).forEach(System.out::println);
以上代码有一个易错点:filter是选择而不是过滤,即filter是选择满足条件的元素。
一、创建Stream
三种常用API:
- 集合-->Stream:stream()
- 数组-->Stream:Stream.of(T t)或者Arrays.stream(T[] t)
- 任意元素-->Stream:Stream.of(T... values)
1 List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana"); 2 Stream<String> streamList = strList.stream();//集合转为stream 3 4 String[] strArray = {"java","c++","c"}; 5 Stream<String> streamArray = Stream.of(strArray);//数组转为Stream 6 Stream<String> streamArray2 = Arrays.stream(strArray);//数组转为Stream 7 8 Stream<String> streamPartArray = Arrays.stream(strArray, 0, 2);//转换部分数组,范围:[0,2) 9 10 Stream<String> streamSelf = Stream.of("python","basic","php");//任意元素
还有一种:用于产生无限流的,Stream.generate(Supplier<T> s)。
二、Stream 2 array/collection/String/map
1、stream2array
1 Stream<String> strStream = Stream.of("java","c++","c","python"); 2 Object[] objectArray = strStream.toArray();//只能返回Object[] 3 String[] strArray = strStream.toArray(String[]::new);//构造器引用(类似于方法引用),可以返回String[]
说明:
通过构造器引用(类似于方法引用),可以构造出具体类型的数组。
2、stream2collection
1 List<String> strList = strStream.collect(Collectors.toList());//返回List 2 Set<String> strSet = strStream.collect(Collectors.toSet());//返回set 3 ArrayList<String> strArrayList = strStream.collect(Collectors.toCollection(ArrayList::new));//收集到指定的List集合,例如收集到ArrayList
说明:
通过构造器引用,可以构造出具体类型的集合。
3、将stream中的元素拼接起来(joining()、joining(","))
1 Stream<String> strStream = Stream.of("java","c++","c","python"); 2 String str = strStream.collect(Collectors.joining());//将所有字符串拼接起来,结果:javac++cpython 3 System.out.println(str); 4 5 String str2 = strStream.collect(Collectors.joining(","));//将所有字符串拼接起来,中间用","隔开,结果:java,c++,c,python 6 System.out.println(str2);
4、stream2map(toMap、toConcurrentMap)
1 Stream<String> strStream = Stream.of("java","c++","c","python"); 2 Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), (x)->0)); 3 //Function.identity()-->返回strStream中的元素,toMap方法的我两个参数都是Function接口型的,所以第二个参数即使只放0,也不能直接写作0,可以使用如上的方式进行操作 4 5 for(String key : map1.keySet()){ 6 System.out.println("key:"+key+"->"+"value:"+map1.get(key)); 7 } 8 //结果 9 /* 10 key:python->value:0 11 key:c++->value:0 12 key:c->value:0 13 key:java->value:0 14 */
说明:
- toMap-->stream转为map
- Function.identity()-->返回stream中的元素
如果key重复的话,这时就会出现问题"duplicate key",采用如下方式解决(增加第三个参数):
1 Stream<String> strStream = Stream.of("java","c++","c","python","java"); 2 Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), //key 3 (x)->0, //value 4 (existingValue, newValue) -> existingValue));//如果key重复,取旧值
需要指定返回map的具体类型(增加第四个参数)。
1 Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), //key 2 (x)->0, //value 3 (existingValue, newValue) -> existingValue,//如果key重复,取旧值 4 TreeMap::new));//返回TreeMap
注意:每一个toMap就会对应一个相应的toConcurrentMap
5、groupingBy partitioningBy
1 /***************************groupingBy partitioningBy**************************/ 2 Stream<Locale> localeStream = Stream.of(Locale.getAvailableLocales()); 3 Map<String, List<Locale>> country2localeList = localeStream.collect(Collectors.groupingBy(Locale::getCountry));//根据国家分组,groupBy的参数是分类器 4 List<Locale> locales = country2localeList.get("CH"); 5 6 Map<String, Set<Locale>> country2localeSet = localeStream.collect(Collectors.groupingBy(Locale::getCountry, Collectors.toSet()));//根据国家分组,groupBy的参数是分类器,返回set 7 Set<Locale> localeSet = country2localeSet.get("CH"); 8 9 Map<Boolean, List<Locale>> country2locales = localeStream.collect(Collectors.partitioningBy(locale->locale.getLanguage().equals("en")));//分成两组,一组为true(即语言是en的),一组为false(即语言不是en的) 10 List<Locale> trueLocale = country2locales.get(true);
三、filter(Predicate p)
注意:是选择而非过滤。
1 Stream<String> streamSelf = Stream.of("python","basic","php"); 2 streamSelf.filter(str->str.startsWith("p")).forEach(System.out::println);
注意:
- stream也是可以foreach的,没必要一定要转化成集合再foreach
更好的写法可能是下边这种:
1 Predicate<String> startCondition = str->str.startsWith("p"); 2 streamSelf.filter(startCondition).forEach(System.out::println);
说明:将条件(通常是lambda表达式)抽取出来。这种方式在多个条件的情况下比较清晰。
注意:函数式接口 = lambda表达式 (即lambda表达式只能返回为函数式接口)
1 Stream<String> s = Stream.of("java1","java3","java","php12"); 2 Predicate<String> condition1 = str->str.length()==5;//条件1 3 Predicate<String> condition2 = str->str.startsWith("j");//条件2 4 s.filter(condition1.and(condition2)).forEach(System.out::println);//and条件
说明:
多条件运算:and or
四、map(Function mapper)
作用:对流中的每一个元素进行操作。
1 Stream<String> streamSelf = Stream.of("python","basic","php"); 2 streamSelf.map(String::toUpperCase).forEach(System.out::println);
说明:将流内的每一个String全部转换为了大写。
五、reduce
作用:对stream中的每一个元素做聚合操作。
1 Stream<Integer> reduceStream = Stream.of(1,2,3,4,5); 2 Optional<Integer> sumOption = reduceStream.reduce((x,y)->x+y);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算(注意:如果stream为null的话,就会产生无效的结果,需要使用Optional接收) 3 //Optional<Integer> sumOption = reduceStream.reduce(Integer::sum);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算 4 5 Integer result = reduceStream.reduce(0, Integer::sum);//0为标识值,即计算:0+1+2+。。+5,如果整个stream为null,就返回标识值。 6 System.out.println(result);
注意:以上是reduce的简单形式,即内联函数是(T,T)->T,即返回值和参数类型是一样的,返回值和参数类型不同的场景需要自己编写函数(用的较少)
六、Optional
两种用法:
- ifPresent(xxx):存在的就执行xxx,不存在就什么都不执行
- orElse(xxx):存在就返回存在的值,不存在就返回xxx(可以理解为是默认值)
1 Stream<String> optionalStream = Stream.of("java","python","basic"); 2 Optional<String> optionValue = optionalStream.filter(str->str.startsWith("p")).findFirst(); 3 optionValue.ifPresent(str->System.out.println(str));//if optionalValue为true,即str存在,则输出str,当然也可以使用如下 4 String str = optionValue.orElse("xxx");//如果optionValue为false,即不存在以p开头的字符串时,使用"xxx"来替代 5 System.out.println(str);
七、limit skip contact
1、limit(long size)
作用:截取stream的前size个元素。
1 Stream<String> streamSelf = Stream.of("python","basic","php"); 2 streamSelf.limit(2).forEach(System.out::println);//截取前两个
2、skip(long size)
作用:跳过stream的钱size个元素
1 Stream<String> streamSelf = Stream.of("python","basic","php"); 2 streamSelf.skip(2).forEach(System.out::println);//跳过前两个
3、contact(Stream<T>,Stream<T>)
作用:拼接两个stream
1 Stream<String> streamSelf = Stream.of("python","basic","php"); 2 Stream<String> streamSelf2 = Stream.of("python2","basic2","php2"); 3 Stream.concat(streamSelf, streamSelf2).forEach(System.out::println);
八、聚合函数 count max min findFirst findAny anyMatch allMatch noneMatch
1 Stream<String> streamSelf = Stream.of("python","basic","php","b"); 2 System.out.println(streamSelf.count());//计算流中的元素个数 3 Optional<String> largest = streamSelf.max(String::compareToIgnoreCase);//寻找最大值 4 if(largest.isPresent()){ 5 System.out.println(largest.get()); 6 }
说明:min函数也一样。
注意:Optional的使用,上边的是最差的一种形式,见"六"。
1 Optional<String> firstMatch = streamSelf.filter(str->str.startsWith("b")).findFirst();//寻找第一个符合条件的元素 2 firstMatch.ifPresent(System.out::println);//这是Optional的第一种用法 3 4 Optional<String> anyMatch = streamSelf.parallel().filter(str->str.startsWith("b")).findAny();//返回集合中符合条件的任意一个元素,对于并行处理非常好(因为多个线程只要有一个线程找到了,整个计算就会结束) 5 if(anyMatch.isPresent()){ 6 System.out.println(anyMatch.get());//这里的结果可能是b,有可能是basic 7 } 8 9 boolean isAnyMatch = streamSelf.parallel().anyMatch(str->str.startsWith("c"));//集合中是否有一个满足条件 10 System.out.println(isAnyMatch); 11 12 Stream<String> streamSelf3 = Stream.of("basic","b"); 13 boolean isAllMatch = streamSelf3.parallel().allMatch(str->str.startsWith("b"));//集合中是否所有元素都满足条件 14 System.out.println(isAllMatch); 15 16 boolean isAllNotMatch = streamSelf.parallel().noneMatch(str->str.startsWith("p"));//集合中是否没有一个元素满足条件 17 System.out.println(isAllNotMatch);
注意:
- optional的最佳用法:ifPresent()-->如果有就输出,如果没有,什么都不做
- parallel():将stream转为并行流,并行流的使用一定要注意线程安全
九、原始类型流
- IntStream:int、short、char、byte、boolean
- LongStream:long
- DoubleStream:double、float
1.3 java8新特性总结
java8中重要的4个新特性:
- Lambda
- Stream
- Optional
- 日期时间API
- 接口方法(default和static方法,jdk9可定义private方法)
一、Lambda
1 import java.util.Comparator; 2 import java.util.function.Consumer; 3 4 /** 5 * @author zhaojigang 6 * @date 2018/5/19 7 */ 8 public class LambdaTest { 9 /** 10 * Lambda 是一个匿名函数。 11 * 1、语法 12 * Lambda表达式引入了操作符为"->",该操作符将Lambda分为两个部分: 13 * 左侧:指定了Lambda表达式需要的所有参数 14 * 右侧:指定了Lambda体,即Lambda表达式要执行的功能。 15 * 16 * 2、示例 17 */ 18 public void testLambda() { 19 /** 20 * 语法格式一:无参,无返回值 21 */ 22 Runnable task = () -> System.out.println("hello lambda"); 23 /** 24 * 语法格式二:一个参数,无返回值 25 * 注意:参数类型可以通过 26 */ 27 Consumer<String> consumer = str -> System.out.println(str); 28 /** 29 * 语法格式三:一个参数,有返回值 30 * 注意:当Lambda体只有一条语句时,省略大括号和return 31 */ 32 Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y); 33 } 34 35 /** 36 * 函数式接口:只包含一个抽象方法的接口。 37 * 1、可以通过Lambda表达式来创建该接口的对象 38 * 2、可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口 39 * 40 * Java内置了四大核心函数式接口: 41 * 1、Consumer<T>:void accept(T t),消费型接口 42 * 2、Supplier<T>:T get(),供给型接口 43 * 3、Function<T, R>:R apply(T t),函数型接口 44 * 4、Predicate<T>:boolean test(T t),断言型接口 45 * 还有部分子接口。 46 */ 47 public void testFunctionalInterface() { 48 Consumer<String> consumer = str -> System.out.println(str); 49 } 50 }
二、Stream
1 import java.util.ArrayList; 2 import java.util.HashMap; 3 import java.util.List; 4 import java.util.Map; 5 import java.util.Optional; 6 import java.util.OptionalLong; 7 import java.util.stream.LongStream; 8 9 /** 10 * @author zhaojigang 11 * @date 2018/5/19 12 */ 13 public class StreamTest { 14 15 static List<Integer> integerList = new ArrayList<Integer>() {{ 16 add(1); 17 add(2); 18 add(3); 19 add(4); 20 add(5); 21 add(5); 22 add(5); 23 }}; 24 25 static List<Integer> integerList2 = new ArrayList<Integer>() {{ 26 add(10); 27 add(20); 28 add(30); 29 }}; 30 31 static Map<String, List<Integer>> map1 = new HashMap<>(); 32 33 static { 34 map1.put("list1", integerList); 35 map1.put("list2", integerList2); 36 } 37 38 /** 39 * 分片与筛选 40 */ 41 public static void test1() { 42 integerList.stream() 43 .filter(x -> x > 2) // 3,4,5,5,5 44 .skip(2) //5,5,5 45 .limit(2) //5,5 短路:一旦获取到2个元素后不再向后迭代 46 .distinct() //5 47 .forEach(System.out::println); 48 } 49 50 /** 51 * 映射 52 * map(Function f):接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素 53 * flatMap(Function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 54 */ 55 public static void test2() { 56 integerList.stream() 57 .map(x -> x + 10) 58 .forEach(System.out::println); 59 60 map1.values().stream() 61 .flatMap(x -> x.stream()) // x是每一个List,flatMap将每一个List的Stream合并起来 62 .forEach(System.out::println); 63 64 } 65 66 /** 67 * 排序 68 * sorted():产生一个新流,其中按自然顺序排序(按照元素的Comparable接口) 69 * sorted(Comparator comp):产生一个新流,其中按比较器顺序排序(按照自定义的Comparator) 70 */ 71 public static void test3() { 72 integerList.stream() 73 .sorted() 74 .forEach(System.out::println); 75 76 integerList.stream() 77 .sorted((x, y) -> { 78 if (x < y) { 79 return 1; 80 } else { 81 return -1; 82 } 83 }) 84 .forEach(System.out::println); 85 86 } 87 88 /** 89 * 查找与匹配 90 * allMatch(Predicate p):检查是否匹配所有元素 91 * anyMatch(Predicate p):检查是否至少匹配一个元素 92 * noneMatch(Predicate p):检查是否没有匹配所有元素 93 * findFirst():返回第一个元素 94 * findAny():返回当前流中的任意元素 95 * count():返回流中元素总数 96 * max(Comparator c):返回流中最大值 97 * min(Comparator c):返回流中最小值 98 */ 99 public static void test4() { 100 final boolean allMatch = integerList.stream().allMatch(x -> x > 4); 101 final boolean anyMatch = integerList.stream().anyMatch(x -> x > 4); 102 final boolean noneMatch = integerList.stream().noneMatch(x -> x > 4); 103 final Optional<Integer> first = integerList.stream().filter(x -> x > 3).findFirst(); 104 final Optional<Integer> any = integerList.stream().filter(x -> x > 3).findAny(); 105 final long count = integerList.stream().filter(x -> x > 4).count(); 106 final Optional<Integer> max = integerList.stream() 107 .max((x, y) -> { 108 if (x < y) { 109 return 1; 110 } else { 111 return -1; 112 } 113 }); 114 115 } 116 117 /** 118 * 规约 119 * <p> 120 * reduce(T iden, BinaryOperator b):可以将流中元素反复结合起来,得到一个值。返回T,其中iden是初始值 121 * reduce(BinaryOperator b):可以将流中元素反复结合起来,得到一个值。返回Optional<T> 122 */ 123 public static void test5() { 124 // 计算:100+1+2+3+4+5+5+5 125 final Integer sum = integerList.stream().reduce(100, (x, y) -> x + y); 126 final Optional<Integer> sumOptional = integerList.stream().reduce((x, y) -> x + y); 127 } 128 129 /** 130 * 收集 131 * 常用: 132 * 1、将流元素收集到List:List<Employee> emps= list.stream().collect(Collectors.toList()); 133 * 2、将流元素收集到Set:List<Employee> emps= list.stream().collect(Collectors.toSet()); 134 * 3、连接流中每个字符串:String str= list.stream().map(Employee::getName).collect(Collectors.joining()); 135 * 4、分组: Map<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus)); 136 * 137 * 不常用: 138 * 1、根据true或false进行分区:Map<Boolean,List<Emp>>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage)); 139 * 2、根据比较器选择最大值:Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); 140 * 3、根据比较器选择最小值:Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); 141 * 4、将流元素收集到任意指定集合:Collection<Employee> emps=list.stream().collect(Collectors.toCollection(ArrayList::new)); 142 * 5、计算流中元素的个数:long count = list.stream().collect(Collectors.counting()); 143 * 6、对流中元素的属性求和:int total=list.stream().collect(Collectors.summingInt(Employee::getSalary)); 144 * 7、计算流中元素Integer属性的平均值:double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary)); 145 */ 146 public static void test6() { 147 } 148 149 /** 150 * 并行流与串行流 151 * 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 152 * 底层:fork/join 153 * Stream API可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换 154 */ 155 public static void test7(){ 156 long start = System.currentTimeMillis(); 157 158 final OptionalLong sum = LongStream.rangeClosed(0, 100000000000L) 159 .parallel() 160 .reduce(Long::sum); 161 162 System.out.println(sum + "-" + (System.currentTimeMillis() - start)); 163 } 164 165 public static void main(String[] args) { 166 test7(); 167 } 168 }
三、Optional
1 import java.util.Optional; 2 3 /** 4 * @author zhaojigang 5 * @date 2018/5/19 6 */ 7 public class OptionalTest { 8 9 public static void main(String[] args) { 10 // String godName = "shijia"; 11 String godName = null; 12 // 常用方式 13 final String god = Optional.ofNullable(godName).orElse("yesu"); 14 System.out.println(god); 15 } 16 }
四、日期时间API
1 import java.time.Duration; 2 import java.time.Instant; 3 import java.time.LocalDateTime; 4 import java.time.format.DateTimeFormatter; 5 6 /** 7 * @author zhaojigang 8 * @date 2018/5/19 9 */ 10 public class TimeTest { 11 12 /** 13 * 一、日期创建: 14 * LocalDate localDate = LocalDate.now(); 15 * LocalTime localTime = LocalTime.now(); 16 * LocalDateTime localDateTime = LocalDateTime.now(); 17 * 18 * LocalDate localDate = LocalDate.of(2016, 10, 26); 19 * LocalTime localTime = LocalTime.of(02, 22, 56); 20 * LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55); 21 * 22 * 二、日期加减运算 23 * plusDays, plusWeeks, plusMonths, plusYears 24 * minusDays, minusWeeks, minusMonths, minusYears 25 * plus, minus 26 * 27 * 三、日期比较计算 28 * isBefore, isAfter 29 * 30 * 四、是否闰年 31 * isLeapYear 32 * 33 * 五、时间戳与时间间隔运算 34 * Instant 时间戳:以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算 35 * Duration:用于计算两个“时间”间隔 36 * Period:用于计算两个“日期”间隔 37 * 38 * 六、时间校正器 39 * TemporalAdjuster/TemporalAdjusters 调整时间:例如获取下一个周日等 40 * 41 * 七、日期解析和格式化 42 * java.time.format.DateTimeFormatter类 43 */ 44 public static void main(String[] args) { 45 /** 46 * 计算时间间隔 47 */ 48 Instant in1 = Instant.now(); 49 Instant in2 = Instant.now(); 50 System.out.println(Duration.between(in1, in2).toMillis()); 51 52 /** 53 * 日期格式化 54 */ 55 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 56 LocalDateTime time1 = LocalDateTime.now(); 57 String formatDateTime = time1.format(formatter); 58 59 /** 60 * 日期解析 61 */ 62 LocalDateTime dateTime = LocalDateTime.parse(formatDateTime, formatter); 63 } 64 }
日期操作我们通常会使用Apache commons包,但是这样就会引入一个包,能够使用java本身的就是用java本身的。
五、接口方法
1 /** 2 * @author zhaojigang 3 * @date 2018/5/19 4 */ 5 public class InterfaceTest { 6 public static void main(String[] args) { 7 MyImpl myClass = new MyImpl(); 8 System.out.println(myClass.getName()); 9 System.out.println(MyInterface.getAge()); 10 } 11 } 12 13 interface MyInterface { 14 default String getName(){ 15 return "nana"; 16 } 17 18 static Integer getAge(){ 19 return 18; 20 } 21 } 22 23 /** 24 * 若一个接口中定义了一个默认方法,而另外一个父类中又定义了一个同名的方法时,取父类 25 * 若一个接口中定义了一个默认方法,而另外一个实现接口中又定义了一个同名的方法时,实现类需要执行重写其中一个 26 */ 27 class MyImpl implements MyInterface { 28 }