JDK1.8 新特性

本文主要介绍了JDK1.8版本中的一些新特性,乃作者视频观后笔记,仅供参考。

jdk1.8新特性知识点:

  • Lambda表达式
  • 函数式接口
  • 方法引用和构造器调用
  • Stream API
  • 接口中的默认方法和静态方法
  • 新时间日期API

在jdk1.8中对hashMap等map集合的数据结构优化。hashMap数据结构的优化
原来的hashMap采用的数据结构是哈希表(数组+链表),hashMap默认大小是16,一个0-15索引的数组,如何往里面存储元素,首先调用元素的hashcode
方法,计算出哈希码值,经过哈希算法算成数组的索引值,如果对应的索引处没有元素,直接存放,如果有对象在,那么比较它们的equals方法比较内容
如果内容一样,后一个value会将前一个value的值覆盖,如果不一样,在1.7的时候,后加的放在前面,形成一个链表,形成了碰撞,在某些情况下如果链表
无限下去,那么效率极低,碰撞是避免不了的
加载因子:0.75,数组扩容,达到总容量的75%,就进行扩容,但是无法避免碰撞的情况发生
在1.8之后,在数组+链表+红黑树来实现hashmap,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入
除了添加之后,效率都比链表高,1.8之后链表新进元素加到末尾
ConcurrentHashMap (锁分段机制),concurrentLevel,jdk1.8采用CAS算法(无锁算法,不再使用锁分段),数组+链表中也引入了红黑树的使用

Lambda表达式

lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码

先来体验一下lambda最直观的优点:简洁代码

  //匿名内部类Comparator<Integer> cpt = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1,o2);}};TreeSet<Integer> set = new TreeSet<>(cpt);System.out.println("=========================");//使用lambda表达式Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);TreeSet<Integer> set2 = new TreeSet<>(cpt2);123456789101112131415

只需要一行代码,极大减少代码量!!

这样一个场景,在商城浏览商品信息时,经常会有条件的进行筛选浏览,例如要选颜色为红色的、价格小于8000千的….

// 筛选颜色为红色
public  List<Product> filterProductByColor(List<Product> list){List<Product> prods = new ArrayList<>();for (Product product : list){if ("红色".equals(product.getColor())){prods.add(product);}}return prods;}// 筛选价格小于8千的
public  List<Product> filterProductByPrice(List<Product> list){List<Product> prods = new ArrayList<>();for (Product product : list){if (product.getPrice() < 8000){prods.add(product);}}return prods;}123456789101112131415161718192021

我们发现实际上这些过滤方法的核心就只有if语句中的条件判断,其他均为模版代码,每次变更一下需求,都需要新增一个方法,然后复制黏贴,假设这个过滤方法有几百行,那么这样的做法难免笨拙了一点。如何进行优化呢?

优化一:使用设计模式

定义一个MyPredicate接口

public interface MyPredicate <T> {boolean test(T t);
}123

如果想要筛选颜色为红色的商品,定义一个颜色过滤类

public class ColorPredicate implements MyPredicate <Product> {private static final String RED = "红色";@Overridepublic boolean test(Product product) {return RED.equals(product.getColor());}12345678

定义过滤方法,将过滤接口当做参数传入,这样这个过滤方法就不用修改,在实际调用的时候将具体的实现类传入即可。

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){List<Product> prods = new ArrayList<>();for (Product prod : list){if (mp.test(prod)){prods.add(prod);}}return prods;}123456789

例如,如果想要筛选价格小于8000的商品,那么新建一个价格过滤类既可

public class PricePredicate implements MyPredicate<Product> {@Overridepublic boolean test(Product product) {return product.getPrice() < 8000;}
}123456

这样实现的话可能有人会说,每次变更需求都需要新建一个实现类,感觉还是有点繁琐呀,那么再来优化一下

优化二:使用匿名内部类

定义过滤方法:

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){List<Product> prods = new ArrayList<>();for (Product prod : list){if (mp.test(prod)){prods.add(prod);}}return prods;}123456789

调用过滤方法的时候:

// 按价格过滤
public void test2(){filterProductByPredicate(proList, new MyPredicate<Product>() {@Overridepublic boolean test(Product product) {return product.getPrice() < 8000;}});
}// 按颜色过滤public void test3(){filterProductByPredicate(proList, new MyPredicate<Product>() {@Overridepublic boolean test(Product product) {return "红色".equals(product.getColor());}});}12345678910111213141516171819

使用匿名内部类,就不需要每次都新建一个实现类,直接在方法内部实现。看到匿名内部类,不禁想起了Lambda表达式。

优化三:使用lambda表达式

定义过滤方法:

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){List<Product> prods = new ArrayList<>();for (Product prod : list){if (mp.test(prod)){prods.add(prod);}}return prods;}123456789

使用lambda表达式进行过滤

@Test
public void test4(){List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);for (Product pro : products){System.out.println(pro);}}1234567

在jdk1.8中还有更加简便的操作 Stream API

优化四:使用Stream API

甚至不用定义过滤方法,直接在集合上进行操作

// 使用jdk1.8中的Stream API进行集合的操作
@Test
public void test(){// 根据价格过滤proList.stream().fliter((p) -> p.getPrice() <8000).limit(2).forEach(System.out::println);// 根据颜色过滤proList.stream().fliter((p) -> "红色".equals(p.getColor())).forEach(System.out::println);// 遍历输出商品名称proList.stream().map(Product::getName).forEach(System.out::println);
}12345678910111213141516171819

Lmabda表达式的语法总结: () -> ();

前置 语法
无参数无返回值 () -> System.out.println(“Hello WOrld”)
有一个参数无返回值 (x) -> System.out.println(x)
有且只有一个参数无返回值 x -> System.out.println(x)
有多个参数,有返回值,有多条lambda体语句 (x,y) -> {System.out.println(“xxx”);return xxxx;};
有多个参数,有返回值,只有一条lambda体语句 (x,y) -> xxxx

口诀:左右遇一省括号,左侧推断类型省

注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念

函数式接口

函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。

什么是函数式接口?
简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface

常见的四大函数式接口

  • Consumer 《T》:消费型接口,有参无返回值
    @Testpublic void test(){changeStr("hello",(str) -> System.out.println(str));}/***  Consumer<T> 消费型接口* @param str* @param con*/public void changeStr(String str, Consumer<String> con){con.accept(str);}12345678910111213
  • Supplier 《T》:供给型接口,无参有返回值
    @Testpublic void test2(){String value = getValue(() -> "hello");System.out.println(value);}/***  Supplier<T> 供给型接口* @param sup* @return*/public String getValue(Supplier<String> sup){return sup.get();}1234567891011121314
  • Function 《T,R》::函数式接口,有参有返回值
    @Testpublic void test3(){Long result = changeNum(100L, (x) -> x + 200L);System.out.println(result);}/***  Function<T,R> 函数式接口* @param num* @param fun* @return*/public Long changeNum(Long num, Function<Long, Long> fun){return fun.apply(num);}123456789101112131415
  • Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型
public void test4(){boolean result = changeBoolean("hello", (str) -> str.length() > 5);System.out.println(result);}/***  Predicate<T> 断言型接口* @param str* @param pre* @return*/public boolean changeBoolean(String str, Predicate<String> pre){return pre.test(str);}1234567891011121314

在四大核心函数式接口基础上,还提供了诸如BiFunction、BinaryOperation、toIntFunction等扩展的函数式接口,都是在这四种函数式接口上扩展而来的,不做赘述。

总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了,贴

方法引用

若lambda体中的内容有方法已经实现了,那么可以使用“方法引用”
也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单

(a) 方法引用
三种表现形式:
\1. 对象::实例方法名
\2. 类::静态方法名
\3. 类::实例方法名 (lambda参数列表中第一个参数是实例方法的调用 者,第二个参数是实例方法的参数时可用)

 public void test() {/***注意:*   1.lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!*   2.若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method**/Consumer<Integer> con = (x) -> System.out.println(x);con.accept(100);// 方法引用-对象::实例方法Consumer<Integer> con2 = System.out::println;con2.accept(200);// 方法引用-类名::静态方法名BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y);BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;Integer result = biFun2.apply(100, 200);// 方法引用-类名::实例方法名BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2);BiFunction<String, String, Boolean> fun2 = String::equals;Boolean result2 = fun2.apply("hello", "world");System.out.println(result2);}12345678910111213141516171819202122232425

(b)构造器引用
格式:ClassName::new

public void test2() {// 构造方法引用  类名::newSupplier<Employee> sup = () -> new Employee();System.out.println(sup.get());Supplier<Employee> sup2 = Employee::new;System.out.println(sup2.get());// 构造方法引用 类名::new (带一个参数)Function<Integer, Employee> fun = (x) -> new Employee(x);Function<Integer, Employee> fun2 = Employee::new;System.out.println(fun2.apply(100));}12345678910111213

©数组引用

格式:Type[]::new

public void test(){// 数组引用Function<Integer, String[]> fun = (x) -> new String[x];Function<Integer, String[]> fun2 = String[]::new;String[] strArray = fun2.apply(10);Arrays.stream(strArray).forEach(System.out::println);
}1234567

Stream API

Stream操作的三个步骤

  • 创建stream
  • 中间操作(过滤、map)
  • 终止操作

stream的创建:

    // 1,校验通过Collection 系列集合提供的stream()或者paralleStream()List<String> list = new ArrayList<>();Strean<String> stream1 = list.stream();// 2.通过Arrays的静态方法stream()获取数组流String[] str = new String[10];Stream<String> stream2 = Arrays.stream(str);// 3.通过Stream类中的静态方法ofStream<String> stream3 = Stream.of("aa","bb","cc");// 4.创建无限流// 迭代Stream<Integer> stream4 = Stream.iterate(0,(x) -> x+2);//生成Stream.generate(() ->Math.random());1234567891011121314151617

Stream的中间操作:

/*** 筛选 过滤  去重*/emps.stream().filter(e -> e.getAge() > 10).limit(4).skip(4)// 需要流中的元素重写hashCode和equals方法.distinct().forEach(System.out::println);/***  生成新的流 通过map映射*/emps.stream().map((e) -> e.getAge()).forEach(System.out::println);/***  自然排序  定制排序*/emps.stream().sorted((e1 ,e2) -> {if (e1.getAge().equals(e2.getAge())){return e1.getName().compareTo(e2.getName());} else{return e1.getAge().compareTo(e2.getAge());}}).forEach(System.out::println);
123456789101112131415161718192021222324252627282930313233

Stream的终止操作:

 /***      查找和匹配*          allMatch-检查是否匹配所有元素*          anyMatch-检查是否至少匹配一个元素*          noneMatch-检查是否没有匹配所有元素*          findFirst-返回第一个元素*          findAny-返回当前流中的任意元素*          count-返回流中元素的总个数*          max-返回流中最大值*          min-返回流中最小值*//***  检查是否匹配元素*/boolean b1 = emps.stream().allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));System.out.println(b1);boolean b2 = emps.stream().anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));System.out.println(b2);boolean b3 = emps.stream().noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));System.out.println(b3);Optional<Employee> opt = emps.stream().findFirst();System.out.println(opt.get());// 并行流Optional<Employee> opt2 = emps.parallelStream().findAny();System.out.println(opt2.get());long count = emps.stream().count();System.out.println(count);Optional<Employee> max = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(max.get());Optional<Employee> min = emps.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(min.get());1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

还有功能比较强大的两个终止操作 reduce和collect
reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以将流中元素反复结合起来,得到一个值

         /***  reduce :规约操作*/List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer count2 = list.stream().reduce(0, (x, y) -> x + y);System.out.println(count2);Optional<Double> sum = emps.stream().map(Employee::getSalary).reduce(Double::sum);System.out.println(sum);
12345678910111213

collect操作:Collect-将流转换为其他形式,接收一个Collection接口的实现,用于给Stream中元素做汇总的方法

        /***  collect:收集操作*/List<Integer> ageList = emps.stream().map(Employee::getAge).collect(Collectors.toList());ageList.stream().forEach(System.out::println);12345678

并行流和串行流

在jdk1.8新的stream包中针对集合的操作也提供了并行操作流和串行操作流。并行流就是把内容切割成多个数据块,并且使用多个线程分别处理每个数据块的内容。Stream api中声明可以通过parallel()与sequential()方法在并行流和串行流之间进行切换。
jdk1.8并行流使用的是fork/join框架进行并行操作

ForkJoin框架

Fork/Join 框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。
关键字:递归分合、分而治之。
采用 “工作窃取”模式(work-stealing):
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线
程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的
处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因
无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果
某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子
问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程
的等待时间,提高了性能.。

/*** 要想使用Fark—Join,类必须继承* RecursiveAction(无返回值)* Or* RecursiveTask(有返回值)
*
*/
public class ForkJoin extends RecursiveTask<Long> {/*** 要想使用Fark—Join,类必须继承RecursiveAction(无返回值) 或者* RecursiveTask(有返回值)** @author Wuyouxin*/private static final long serialVersionUID = 23423422L;private long start;private long end;public ForkJoin() {}public ForkJoin(long start, long end) {this.start = start;this.end = end;}// 定义阙值private static final long THRESHOLD = 10000L;@Overrideprotected Long compute() {if (end - start <= THRESHOLD) {long sum = 0;for (long i = start; i < end; i++) {sum += i;}return sum;} else {long middle = (end - start) / 2;ForkJoin left = new ForkJoin(start, middle);//拆分子任务,压入线程队列left.fork();ForkJoin right = new ForkJoin(middle + 1, end);right.fork();//合并并返回return left.join() + right.join();}}/*** 实现数的累加*/@Testpublic void test1() {//开始时间Instant start = Instant.now();//这里需要一个线程池的支持ForkJoinPool pool = new ForkJoinPool();ForkJoinTask<Long> task = new ForkJoin(0L, 10000000000L);// 没有返回值     pool.execute();// 有返回值long sum = pool.invoke(task);//结束时间Instant end = Instant.now();System.out.println(Duration.between(start, end).getSeconds());}/*** java8 并行流 parallel()*/@Testpublic void test2() {//开始时间Instant start = Instant.now();// 并行流计算    累加求和LongStream.rangeClosed(0, 10000000000L).parallel().reduce(0, Long :: sum);//结束时间Instant end = Instant.now();System.out.println(Duration.between(start, end).getSeconds());}@Testpublic void test3(){List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);list.stream().forEach(System.out::print);list.parallelStream().forEach(System.out::print);}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798

展示多线程的效果:

@Testpublic void test(){// 并行流 多个线程执行List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);numbers.parallelStream().forEach(System.out::print);//System.out.println("=========================");numbers.stream().sequential().forEach(System.out::print);}12345678910111213

Optional容器

使用Optional容器可以快速的定位NPE,并且在一定程度上可以减少对参数非空检验的代码量。
1
/***      Optional.of(T t); // 创建一个Optional实例*      Optional.empty(); // 创建一个空的Optional实例*      Optional.ofNullable(T t); // 若T不为null,创建一个Optional实例,否则创建一个空实例*      isPresent();    // 判断是够包含值*      orElse(T t);   //如果调用对象包含值,返回该值,否则返回T*      orElseGet(Supplier s);  // 如果调用对象包含值,返回该值,否则返回s中获取的值*      map(Function f): // 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty();*      flatMap(Function mapper);// 与map类似。返回值是Optional**      总结:Optional.of(null)  会直接报NPE*/Optional<Employee> op = Optional.of(new Employee("zhansan", 11, 12.32, Employee.Status.BUSY));System.out.println(op.get());// NPEOptional<Employee> op2 = Optional.of(null);System.out.println(op2);
@Testpublic void test2(){Optional<Object> op = Optional.empty();System.out.println(op);// No value presentSystem.out.println(op.get());}
@Testpublic void test3(){Optional<Employee> op = Optional.ofNullable(new Employee("lisi", 33, 131.42, Employee.Status.FREE));System.out.println(op.get());Optional<Object> op2 = Optional.ofNullable(null);System.out.println(op2);// System.out.println(op2.get());}@Testpublic void test5(){Optional<Employee> op1 = Optional.ofNullable(new Employee("张三", 11, 11.33, Employee.Status.VOCATION));System.out.println(op1.orElse(new Employee()));System.out.println(op1.orElse(null));}@Testpublic void test6(){Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));op1 = Optional.empty();Employee employee = op1.orElseGet(() -> new Employee());System.out.println(employee);}@Testpublic void test7(){Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));System.out.println(op1.map( (e) -> e.getSalary()).get());}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

接口中可以定义默认实现方法和静态方法

在接口中可以使用default和static关键字来修饰接口中定义的普通方法

public interface Interface {default  String getName(){return "zhangsan";}static String getName2(){return "zhangsan";}
}
12345678910

在JDK1.8中很多接口会新增方法,为了保证1.8向下兼容,1.7版本中的接口实现类不用每个都重新实现新添加的接口方法,引入了default默认实现,static的用法是直接用接口名去调方法即可。当一个类继承父类又实现接口时,若后两者方法名相同,则优先继承父类中的同名方法,即“类优先”,如果实现两个同名方法的接口,则要求实现类必须手动声明默认实现哪个接口中的方法。

新的日期API LocalDate | LocalTime | LocalDateTime

新的日期API都是不可变的,更使用于多线程的使用环境中

    @Testpublic void test(){// 从默认时区的系统时钟获取当前的日期时间。不用考虑时区差LocalDateTime date = LocalDateTime.now();//2018-07-15T14:22:39.759System.out.println(date);System.out.println(date.getYear());System.out.println(date.getMonthValue());System.out.println(date.getDayOfMonth());System.out.println(date.getHour());System.out.println(date.getMinute());System.out.println(date.getSecond());System.out.println(date.getNano());// 手动创建一个LocalDateTime实例LocalDateTime date2 = LocalDateTime.of(2017, 12, 17, 9, 31, 31, 31);System.out.println(date2);// 进行加操作,得到新的日期实例LocalDateTime date3 = date2.plusDays(12);System.out.println(date3);// 进行减操作,得到新的日期实例LocalDateTime date4 = date3.minusYears(2);System.out.println(date4);}
1234567891011121314151617181920212223242526@Testpublic void test2(){// 时间戳  1970年1月1日00:00:00 到某一个时间点的毫秒值// 默认获取UTC时区Instant ins = Instant.now();System.out.println(ins);System.out.println(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());System.out.println(System.currentTimeMillis());System.out.println(Instant.now().toEpochMilli());System.out.println(Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant().toEpochMilli());}12345678910111213@Testpublic void test3(){// Duration:计算两个时间之间的间隔// Period:计算两个日期之间的间隔Instant ins1 = Instant.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}Instant ins2 = Instant.now();Duration dura = Duration.between(ins1, ins2);System.out.println(dura);System.out.println(dura.toMillis());System.out.println("======================");LocalTime localTime = LocalTime.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}LocalTime localTime2 = LocalTime.now();Duration du2 = Duration.between(localTime, localTime2);System.out.println(du2);System.out.println(du2.toMillis());}1234567891011121314151617181920212223242526272829
@Testpublic void test4(){LocalDate localDate =LocalDate.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}LocalDate localDate2 = LocalDate.of(2016,12,12);Period pe = Period.between(localDate, localDate2);System.out.println(pe);}1234567891011121314@Testpublic void test5(){// temperalAdjust 时间校验器// 例如获取下周日  下一个工作日LocalDateTime ldt1 = LocalDateTime.now();System.out.println(ldt1);// 获取一年中的第一天LocalDateTime ldt2 = ldt1.withDayOfYear(1);System.out.println(ldt2);// 获取一个月中的第一天LocalDateTime ldt3 = ldt1.withDayOfMonth(1);System.out.println(ldt3);LocalDateTime ldt4 = ldt1.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));System.out.println(ldt4);// 获取下一个工作日LocalDateTime ldt5 = ldt1.with((t) -> {LocalDateTime ldt6 = (LocalDateTime)t;DayOfWeek dayOfWeek = ldt6.getDayOfWeek();if (DayOfWeek.FRIDAY.equals(dayOfWeek)){return ldt6.plusDays(3);}else if (DayOfWeek.SATURDAY.equals(dayOfWeek)){return ldt6.plusDays(2);}else {return ldt6.plusDays(1);}});System.out.println(ldt5);}123456789101112131415161718192021222324252627282930313233@Testpublic void test6(){// DateTimeFormatter: 格式化时间/日期// 自定义格式LocalDateTime ldt = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");String strDate1 = ldt.format(formatter);String strDate = formatter.format(ldt);System.out.println(strDate);System.out.println(strDate1);// 使用api提供的格式DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;LocalDateTime ldt2 = LocalDateTime.now();String strDate3 = dtf.format(ldt2);System.out.println(strDate3);// 解析字符串to时间DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime time = LocalDateTime.now();String localTime = df.format(time);LocalDateTime ldt4 = LocalDateTime.parse("2017-09-28 17:07:05",df);System.out.println("LocalDateTime转成String类型的时间:"+localTime);System.out.println("String类型的时间转成LocalDateTime:"+ldt4);}12345678910111213141516171819202122232425// ZoneTime  ZoneDate       ZoneDateTime@Testpublic void test7(){LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));System.out.println(now);LocalDateTime now2 = LocalDateTime.now();ZonedDateTime zdt = now2.atZone(ZoneId.of("Asia/Shanghai"));System.out.println(zdt);Set<String> set = ZoneId.getAvailableZoneIds();set.stream().forEach(System.out::println);}12345678910111213

补充:

表示日期的LocalDate
表示时间的LocalTime
表示日期时间的LocalDateTime

新的日期API的几个优点:

 * 之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum* java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。* java.util.Date是一个“万能接口”,它包含日期、时间,还有毫秒数,更加明确需求取舍* 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对。
1234
  • LocalDate
public static void localDateTest() {//获取当前日期,只含年月日 固定格式 yyyy-MM-dd    2018-05-04LocalDate today = LocalDate.now();// 根据年月日取日期,5月就是5,LocalDate oldDate = LocalDate.of(2018, 5, 1);// 根据字符串取:默认格式yyyy-MM-dd,02不能写成2LocalDate yesteday = LocalDate.parse("2018-05-03");// 如果不是闰年 传入29号也会报错LocalDate.parse("2018-02-29");}1234567891011121314
  • LocalDate常用转化
    /*** 日期转换常用,第一天或者最后一天...*/public static void localDateTransferTest(){//2018-05-04LocalDate today = LocalDate.now();// 取本月第1天: 2018-05-01LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());// 取本月第2天:2018-05-02LocalDate secondDayOfThisMonth = today.withDayOfMonth(2);// 取本月最后一天,再也不用计算是28,29,30还是31: 2018-05-31LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());// 取下一天:2018-06-01LocalDate firstDayOf2015 = lastDayOfThisMonth.plusDays(1);// 取2018年10月第一个周三 so easy?:  2018-10-03LocalDate thirdMondayOf2018 = LocalDate.parse("2018-10-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.WEDNESDAY));}1234567891011121314151617
  • LocalTime
 public static void localTimeTest(){//16:25:46.448(纳秒值)LocalTime todayTimeWithMillisTime = LocalTime.now();//16:28:48 不带纳秒值LocalTime todayTimeWithNoMillisTime = LocalTime.now().withNano(0);LocalTime time1 = LocalTime.parse("23:59:59");}1234567
  • LocalDateTime
public static void localDateTimeTest(){//转化为时间戳  毫秒值long time1 = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();long time2 = System.currentTimeMillis();//时间戳转化为localdatetimeDateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");System.out.println(df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time1),ZoneId.of("Asia/Shanghai"))));}12345678910

JDK1.8 新特性(全)相关推荐

  1. java基础知识总结:基础知识、面向对象、集合框架、多线程、jdk1.5新特性、IO流、网络编程

    目录 一.基础知识: 二.面向对象 三.集合框架 四.多线程: 五.jdk1.5的新特性 六.IO流 七.网络编程: 一.基础知识: 1.JVM.JRE和JDK的区别: JVM(Java Virtua ...

  2. jdk1.8新特性的应用-Stream 的终止操作

    jdk1.8新特性的应用-Stream 的终止操作 public class TestStreamApi4 {List<Employee> emps = Arrays.asList(new ...

  3. jdk1.8新特性_Lambda表达式的引入

    jdk1.8新特性_Lambda表达式的引入 引入 需求: 获取工资大于20000的员工信息 public class Employee {private String name;private in ...

  4. jdk1.5新特性5之枚举之模拟枚举类型

    一 简单应用 package cn.xy.Enum; public enum TrafficLamp {  RED,GREEN,YELLOW; } TrafficLamp red = TrafficL ...

  5. java 1.7 可变参数,JDK1.7新特性(2):异常和可变长参数处理

    异常 jdk1.7对try--catch--finally的异常处理模式进行了增强,下面我们依次来看增强的方面. 1. 为了防止异常覆盖,给Throwable类增加了addSuppressed方法,可 ...

  6. JAVA day20、21 双列集合Map<K,V>:HashMap,LinkedHashMap,TreeMap,Hashtable, ConcurrentHashMap;JDK1.9新特性

    一.Map<K,V> Java提供了专⻔的集合类⽤来存放这种这种⼀⼀对应的关系,叫做映射对象,即 java.util.Map 接⼝. 类型参数: K - 此映射所维护的键的类型 V - 映 ...

  7. JDK1.6“新“特性Instrumentation之JavaAgent

    JDK1.6"新"特性Instrumentation之JavaAgent 文章目录 JDK1.6"新"特性Instrumentation之JavaAgent 简 ...

  8. 黑马程序员————高新技术————JDK1.5新特性

    ----------------------ASP.Net+Android+IOS开发----------------------期待与您交流! JDK1.5新特性 一:静态导入 l  Import语 ...

  9. JDK-1.5_新特性

    1.泛型(Generics) 泛型是JDK1.5中一个最"酷"的特征.通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastExceptions的可能.在JD ...

最新文章

  1. Oracle Sequence用plsql修改
  2. SAP Fiori pageSet请求的处理原理
  3. 2020年了,再不会Https就老了
  4. 【渝粤题库】广东开放大学 静态网页技术 形成性考核
  5. python 持续集成方案_Jenkins+Python+GitLab持续集成
  6. 字符串数组转换为整型数组
  7. 信息学奥赛一本通C++语言——1016: 整型数据类型存储空间大小
  8. JavaGUI版本销售管理系统
  9. linux系统下的权限知识梳理
  10. Win10重装后电脑关不了机如何解决
  11. 移动端适配的理解——REM方案
  12. 未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)...
  13. 微信开发者工具安装教程
  14. AI智能电话机器人源码搭建揭秘!
  15. usaco3.4.3 Raucous Rockers
  16. python卸载库命令_python常用删除库的方法
  17. codevs 4939 欧拉函数
  18. 解除win10防火墙对软件的误杀
  19. java迅雷下载excel,Asp.net生成Excel文件并下载(更新:解决使用迅雷下载页面而不是文件的问题)...
  20. SecureCRT win7 安装破解使用

热门文章

  1. 数组重复次数最多的元素递归_使用递归计算链接列表中元素的出现次数
  2. Python | 程序从列表中删除重复的元素
  3. 京东自动下单软件_黄牛软件自动下单秒杀商品 警方用科技手段打击
  4. lol最克制诺手的英雄_LOL:究竟有没有完美克制诺手的英雄?时光上单或可一战?...
  5. python预定义_【Python】python类中方法的预定义
  6. 绘图的尺寸_Auto CAD机械绘图尺寸标注教程1(尺寸标注简介)
  7. mcq 队列_MCQ | 基础知识 免费和开源软件| 套装3
  8. Java中操作Excel的3种方法,太好用了!
  9. 第 6-2 课:SpringMVC 核心 + 面试题
  10. 8种常见SQL错误用法,你犯过几个?