java8新特性
1.HashMap和HashSet
如果说当某一个链表的大小大于8,总容量大于64,那么就会把链表转换成红黑树结构(二叉树的一种),除了添加以外其他的效率都比链表快,所以现在的结构是数组加链表加红黑树
2.ConcurrentHashMap<K,V>
使用大量的cas算法,且取消原来的16段机制,采用了链表和红黑树
3.方法区
原来称为非堆(但是占用jvm空间),现在直接分离出来了叫做元空间,直接占用物理内存。
4.lambda表达式
函数式接口:只包含一个抽象方法的接口,称为函数式接口,使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口。
适用前提条件:必须是一个函数式接口
定义:lambda表达式表示的是一个匿名的函数,Lambda 操作符“->”左侧:指定了Lambda 表达式需要的所有参数,右侧:指定了Lambda 体(匿名函数方法的方法体),即Lambda 表达式要执行的功能。
左侧:在无参的条件下(),有参只有一个参数的前提下可以写成(x),当然也可以去掉()写成x,多个参数的情况下都需要带()
右侧:无返回值只用一条语句可以不带{},多条语句需要带{},有返回值只有一条语句无{}情况下无需写return,多条或者有{}时需要写rreturn
原因:在加载编译的时候会自判断后编译成class字节码文件,在效率上在以前的基础上并没有提升,只是书写较为方便
public class LambdaTest1 {
public static void testA(LambdaTest1A la){
la.testA();
}
public static void main(String[] args) {
testA(()->System.out.println("hello testA"));
ArrayList<Integer> list = new ArrayList<>();
list.add(321);
list.add(123);
list.add(342);
list.add(112);
//Collections.sort(list,(x,y)->x-y);从小到大
Collections.sort(list,(x,y)->y-x);//从大到小
System.out.println(list);
}
}
interface LambdaTest1A{
void testA();
}
//策略设计模式
public class LambdaTest2 {
public static List<LambdaTest2Person> test(List<LambdaTest2Person> list, Predicate<LambdaTest2Person> t) {
ArrayList<LambdaTest2Person> list2 = new ArrayList<>();
for (LambdaTest2Person lambdaTest2Person : list) {
if (t.test(lambdaTest2Person)) {
list2.add(lambdaTest2Person);
}
}
return list2;
}
public static void main(String[] args) {
ArrayList<LambdaTest2Person> list = new ArrayList<>();
list.add(new LambdaTest2Person("张三", 24, 3333));
list.add(new LambdaTest2Person("李四", 34, 8888));
list.add(new LambdaTest2Person("王五", 15, 5555));
list.add(new LambdaTest2Person("赵六", 34, 6666));
//List<LambdaTest2Person> test = test(list, (x) -> x.getAge() > 30);
//System.out.println(test);// 年龄大于35岁的
Collections.sort(list, (x, y) -> {
if (x.getAge() == y.getAge()) {
return x.getSalary() - y.getSalary();
}
return x.getAge() - y.getAge();
});// 先按年龄从小到大排列,年龄相同那么按工资从小到大排列
for (LambdaTest2Person lambdaTest2Person : list) {
System.out.println(lambdaTest2Person);
}
}
}
class LambdaTest2Person {
private String name;
private int age;
private int salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public LambdaTest2Person(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public LambdaTest2Person() {
}
@Override
public String toString() {
return "LambdaTest2Person [name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
4.java8内置的函数式接口
Consumer<T> void accept(T t)
Supplier<T> T get()
Function<T, R> R apply(T t)
Predicate<T> boolean test(T t);
BiFunction<T,U,R> R apply(T t,U u)
UnaryOperator<T> T apply(T t)
BinaryOperator<T> T apply(T t1,T t2)
BiConsumer<T,U> void accept(T t,U u)
ToIntFunction<T> 参数T 返回值 int
IntFunction<R> 参数int 返回R
public class LambdaTest3 {
public static void main(String[] args) {
Consumer<String> cm=(x)->System.out.println(x);
cm.accept("consumer");
Supplier<String> sp=()->"Supplier";
System.out.println(sp.get());
Function<String, Integer> fu= x-> Integer.valueOf(x);
System.out.println(fu.apply("12"));
Predicate<Integer> pr=(x)-> x>0;
System.out.println(pr.test(5));
BiFunction<Integer,Integer, Integer> bi=(x,y)->x+y;
System.out.println(bi.apply(2, 3));
}
}
5.方法引用与构造器引用及数组引用
方法引用
对象::实例方法 ; 类::静态方法 ;类::实例方法 ; 构造器引用 ; 类名 :: new ; 数组引用 ; 类型[] :: new
public class LambdaTest4 {
public static void main(String[] args) {
//自我推测是建立在编译的前提下的,编译时一行一行的,例如如下
String [] str={"a","b"};//成立
//str={"a","b"};//编译不通过
//编译时能自我推测 对象::实例方法
Consumer<String> cm=System.out::println;
cm.accept("Consumer");
//类::静态方法,编译时一行一行的
BiFunction<Integer,Integer, Integer> bi=Integer::compare;
System.out.println(bi.apply(1, 2));
//类名实例方法
Function<LambdaTest2Person, Integer> fu=LambdaTest2Person::getAge;
System.out.println(fu.apply(new LambdaTest2Person("张三", 23, 3333)));
//类名::new
Supplier<LambdaTest2Person> person=LambdaTest2Person::new;
//无参构造
LambdaTest2Person lambdaTest2Person = person.get();
System.out.println(lambdaTest2Person);
//类型[] :: new
Function<Integer, LambdaTest2Person[]> fun2 = LambdaTest2Person[] :: new;
LambdaTest2Person[] emps = fun2.apply(20);
System.out.println(emps.length);
}
}
6.stream流
定义:数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
特点:Stream 自己不会存储元素。
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
也就是说需要结束以后才有结果
public class StreamTest2 {
public static void main(String[] args) {
//获取流的方式1
ArrayList<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
// 获取流的方式2
String[] strs = new String[10];
Stream<String> stream2 = Arrays.stream(strs);
// 获取流的方式3
Stream<String> of = Stream.of("a", "b");
// 创建无线流
// 迭代 static <T> UnaryOperator<T> identity() {return t -> t;},0表示起始值
Stream<Integer> iterate = Stream.iterate(0, (x) -> x - 2);
iterate.limit(10).forEach(System.out::println);
System.out.println("-----------------");
// 创建无限流
// 生成
//T get();
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.limit(10).forEach(System.out::println);
}
}
public class StreamTest1 {
public static void main(String[] args) {
ArrayList<LambdaTest2Person> list = new ArrayList<>();
list.add(new LambdaTest2Person("张三", 24, 3333));
list.add(new LambdaTest2Person("李四", 34, 8888));
list.add(new LambdaTest2Person("王五", 15, 5555));
list.add(new LambdaTest2Person("赵六", 34, 6666));
Stream<LambdaTest2Person> stream = list.stream();
Stream<LambdaTest2Person> stream1 = list.stream();
Stream<LambdaTest2Person> stream2 = list.stream();
Stream<LambdaTest2Person> stream3 = list.stream();
// filter-- boolean test(T t);
stream.filter((x)->x.getAge()>25).forEach(System.out::println);
System.out.println("-----------------------");
/*
* LambdaTest2Person [name=李四, age=34, salary=8888]
* LambdaTest2Person [name=赵六, age=34, salary=6666]
*/
//limit 显示的个数
stream1.filter((x)->x.getAge()>25).limit(1).forEach(System.out::println);
//LambdaTest2Person [name=李四, age=34, salary=8888]
System.out.println("-----------------------");
//skip跳过几个
stream2.filter((x)->x.getAge()>25).skip(1).forEach(System.out::println);
//LambdaTest2Person [name=赵六, age=34, salary=6666]
System.out.println("-----------------------");
//distinct()根据hashcode去重,需要重写hashcode,这里就根据相同年龄去重
stream3.filter((x)->x.getAge()>25).distinct().forEach(System.out::println);
//LambdaTest2Person [name=李四, age=34, salary=8888]
}
}
class LambdaTest2Person {
private String name;
private int age;
private int salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public LambdaTest2Person(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public LambdaTest2Person() {
}
@Override
public String toString() {
return "LambdaTest2Person [name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
//hashcode根据年龄去重
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LambdaTest2Person other = (LambdaTest2Person) obj;
if (age != other.age)
return false;
return true;
}
}
public class StreamTest2 {
public static Stream<Character> toUpper(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character character : str.toUpperCase().toCharArray()) {
list.add(character);
}
return list.stream();
}
public static void main(String[] args) {
System.out.println("----------");
ArrayList<LambdaTest2Person> list = new ArrayList<>();
list.add(new LambdaTest2Person("张三", 24, 3333));
list.add(new LambdaTest2Person("李四", 34, 8888));
list.add(new LambdaTest2Person("王五", 15, 5555));
list.add(new LambdaTest2Person("赵六", 34, 6666));
// map逐个遍历映射 获取名字 张三 李四 王五 赵六
List<String> collect2 = list.stream().map((x) -> x.getName()).collect(Collectors.toList());
collect2.stream().forEach(System.out::println);
System.out.println("----------");
//flatMap与map的区别
//首先是map 返回的是 Stream<Stream<Character>>
Stream<Stream<Character>> map = Stream.of("aa","bb").map(StreamTest2::toUpper);
//然后是flatMap Stream<Character>
Stream<Character> flatMap = Stream.of("aa","bb").flatMap(StreamTest2::toUpper);
// sort排序 按年龄排序 王五 张三 李四 赵六
System.out.println("----------");
list.stream().sorted((x, y) -> x.getAge() - y.getAge()).map((x) -> x.getName()).collect(Collectors.toList())
.forEach(System.out::println);
//count 统计 2 2
Long collect = Stream.of(1, 2, 3, 4, 5).filter((x) -> x > 3).map((x) -> 1).collect(Collectors.counting());
long count = Stream.of(1, 2, 3, 4, 5).filter((x) -> x > 3).map((x) -> 1).count();
System.out.println(collect);
System.out.println(count);
System.out.println("----------");
//allMatch 是否所有的都匹配 false
boolean allMatch = list.stream().allMatch((x)-> "张三".equals (x.getName()));
System.out.println(allMatch);
//anyMatch 是否一个匹配 true
boolean anyMatch = list.stream().anyMatch((x)-> "张三".equals (x.getName()));
System.out.println(anyMatch);
//noneMatch 没有匹配 false
boolean noneMatch = list.stream().noneMatch((x)-> "张三".equals (x.getName()));
System.out.println(noneMatch);
System.out.println("----------");
//findFirst() 返回第一个元素 张三
String string = list.stream().map((x)->x.getName()).findFirst().get();
System.out.println(string);
//findAny() 返回年龄为34的其中的任何一个人
LambdaTest2Person lambdaTest2Person = list.stream().filter((x)->x.getAge()==34).findAny().get();
System.out.println(lambdaTest2Person);
//返回最大值(也有可能是最小值) 这个是根据排序来的
Integer integer = Stream.of(1,3,2,4,10,3,2).max((x,y)->x-y).get();
System.out.println(integer);
//返回最小值(也有可能是最大值) 这个是根据排序来的
Integer integer1 = Stream.of(1,3,2,4,10,3,2).max(Integer::compare).get();
System.out.println(integer1);
System.out.println("----------");
//reduce 根据所写的逐个计算,下面是求和 21 31
Integer integer2 = Stream.of(1,2,3,4,5,6).reduce((x,y)->x+y).get();
System.out.println(integer2);
//10表示起始值
Integer integer3 = Stream.of(1,2,3,4,5,6).reduce(10,(x,y)->x+y);
System.out.println(integer3);
}
}
public class StreamTest4 {
public static void main(String[] args) {
// collect(Collector c) 这个可以求和,平均值,求最大值,分组,保存到集合等
// 求平均值
Double collect = Stream.of(1, 3, 2, 4, 6).filter((x) -> x > 3).collect(Collectors.averagingInt((x) -> x));
System.out.println(collect);
System.out.println("----------");
// 去重1 2 3 4 6
Stream.of(1, 3, 2, 4, 6, 6, 6, 4).collect(Collectors.toSet()).forEach(System.out::println);
;
System.out.println("----------");
// 先去重后分组 {大于3=[4, 6], 小于3=[1, 2, 3]}
Map<String, List<Integer>> collect2 = Stream.of(1, 3, 2, 4, 6, 6, 6, 4).collect(Collectors.toSet()).stream()
.collect(Collectors.groupingBy((x) -> {
if (x > 3) {
return "大于3";
} else {
return "小于3";
}
}));
System.out.println(collect2);
// 多级分组
ArrayList<LambdaTest2Person> list = new ArrayList<>();
list.add(new LambdaTest2Person("张三", 24, 3333));
list.add(new LambdaTest2Person("李四", 34, 8888));
list.add(new LambdaTest2Person("王五", 15, 5555));
list.add(new LambdaTest2Person("赵六", 34, 6666));
Map<String, Map<String, List<LambdaTest2Person>>> collect3 = list.stream().collect(Collectors.groupingBy((x) -> {
if (x.getAge() > 25) {
return "大于25";
} else {
return "小于25";
}
}, Collectors.groupingBy((x) -> {
if (x.getSalary() > 4000) {
return "大于4000";
}else {
return "小于4000";
}
})));
//{大于25={大于4000=[LambdaTest2Person [name=李四, age=34, salary=8888], LambdaTest2Person [name=赵六, age=34, salary=6666]]},
//小于25={大于4000=[LambdaTest2Person [name=王五, age=15, salary=5555]], 小于4000=[LambdaTest2Person [name=张三, age=24, salary=3333]]}}
System.out.println(collect3);
}
}
7.java8的局部内部类的变更
public static void main(String[] args) {
//当局部内部类使用外部的变量是会自动的添加final,在jdk1.7之前需要手动的添加
int i=3;//在jdk1.7之前 这个前面需要添加 final ,但在jdk1.8后会自己添加
// i=5//编译错误
class LocalInnerTest{
public void test(){
System.out.println(i);
}
}
}
8.fork/join框架
fork/join,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join 汇总.
工作窃取模式,充分利用多核线程;
工作窃取:当一个线程执行完了,别的没有执行完,那么该线程会随机的去别的线程的末尾进行窃取工作任务,前提是多核cpu
//jdk1.7之前的算法 传统的算法
public class ForkJoinCalculate extends RecursiveTask<Long> {
public static void main(String[] args) {
long start = System.currentTimeMillis();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(0L, 10000000000L);
long sum = pool.invoke(task);
System.out.println(sum);
long end = System.currentTimeMillis();
System.out.println("耗费的时间为: " + (end - start));
}
private static final long serialVersionUID = 13475679780L;
private long start;
private long end;
private static final long THRESHOLD = 100000L; // 临界值
public ForkJoinCalculate(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start;
if (length <= THRESHOLD) {
long sum = 0;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long middle = (start + end) / 2;
ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
left.fork(); // 拆分,并将该子任务压入线程队列
ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
right.fork();
return left.join() + right.join();
}
}
}
public class NewForkJoin {
@Test
//顺序流,单线程的
//parallel() 与sequential() 在并行流与顺序流之间进行切换。
public void serialStream(){
long asLong = LongStream.rangeClosed(0, 10000000L).reduce(Long::sum).getAsLong();
long sum = LongStream.rangeClosed(0, 10000000L).sum();
System.out.println(asLong);
System.out.println(sum);
}
@Test
//并行流 多线程的
public void parallelStream1(){
long sum = LongStream.rangeClosed(0, 10000000L).parallel().sum();
System.out.println(sum);
}
}
9.optional
目的:尽量的减少空指针异常,属于一个容器类,表示一个值存在或者不存在
public class OptionalTest {
public static void main(String[] args) {
//Optional<String> of = Optional.of(null);// 创建一个 Optional 实例,也会报异常,指定在这一行
Optional<Object> empty = Optional.empty();//创建一个空的 Optional 实例
System.out.println(empty.toString());//Optional.empty
Optional<Object> ofNullable = Optional.ofNullable(null);//若 t 不为 null,创建 Optional 实例,否则创建空实例
Object orElse = Optional.ofNullable(null).orElse("大帅哥");//如果调用对象包含值,返回该值,否则返回t
System.out.println(orElse);//大帅哥
boolean present = Optional.ofNullable(null).isPresent();// 判断是否包含值
System.out.println(present);//false
Object orElseGet = Optional.ofNullable(null).orElseGet(()->"大帅哥");//orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
System.out.println(orElseGet);//大帅哥
//map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
//flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
}
}
10.接口中的新定义
类优先,接口中都实现,那么就按需加载(需要时指定),在Java 8中,在接口中添加静态方法带来了一个限制 :这些方法不能由实现它的类继承。
public class InterfaceTest extends InterfaceTestC implements InterfaceTestA,InterfaceTestB{
public static void main(String[] args) {
InterfaceTest interfaceTest = new InterfaceTest();
interfaceTest.testA();//InterfaceTestC:testA优先使用类中的方法
interfaceTest.testB();//InterfaceTestB---Override--testB,优先使用类中的方法
}
@Override
public void testB() {
System.out.println("InterfaceTestB---Override--testB");
}
@Override
public void testC() {
InterfaceTestA.super.testC();//多个需要重写一个使用的方法,静态方法需要用接口名调用
}
}
interface InterfaceTestA {
static void testA() {// 没有默认会添加public,只能是public的
System.out.println("InterfaceTestA:testA");
}
default void testB() {/// 没有默认会添加public,只能是public的
System.out.println("InterfaceTestA:testB");
}
default void testC() {// 没有默认会添加public,只能是public的
System.out.println("InterfaceTestA:testC");
}
}
interface InterfaceTestB {
void testB();// 默认添加public abstract
default void testC() {// 没有默认会添加public,只能是public的
System.out.println("InterfaceTestB:testC");
}
}
class InterfaceTestC {
void testA() {// 没有默认会添加public,只能是public的
System.out.println("InterfaceTestC:testA");
}
}
11.重复注解
java8后可以重复注解@Repeatable
public class AnnotationTest {
@MyAnnotation("a") // @Repeatable没有这个之前,不能按如下这么写
@MyAnnotation("b")
public void test() {
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {// 获取方法上的注解
Class<? extends AnnotationTest> class1 = new AnnotationTest().getClass();
Method method = class1.getMethod("test");
// MyAnnotation annotation =
// method.getAnnotation(MyAnnotation.class);//只有一次注解的时候能这么做,重复注解的则不行null
MyAnnotation[] annotationsByType = method.getAnnotationsByType(MyAnnotation.class);// 重复注解可以这样
for (MyAnnotation myAnnotation : annotationsByType) {
System.out.println(myAnnotation.value());
}
}
}
@Repeatable(MyAnnotations.class)//添加该注解,需要一个该注解的容器,例如@interface MyAnnotations MyAnnotation[] value();
@Target({ ElementType.METHOD, ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "adu";
}
@Target({ ElementType.METHOD, ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotations {
MyAnnotation[] value();
}
12.新时间api
java8的时间api先线程安全的,而以前的是线程不安全的
//存在线程安全问题,java.util.concurrent.ExecutionException异常偶尔会出现;
public class OldTimeTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy-MM-dd");
FutureTask<Date> futureTask = new FutureTask<>(() -> {
return sdf.parse("2018-5-5");
});
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
Future<?> submit2 = newFixedThreadPool.submit(futureTask);
System.out.println(submit2.get());// null
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return sdf.parse("2018-5-5");
}
};
List<Future<Date>> list = new ArrayList<>();
for (int i = 0; i < 9; i++) {
list.add(newFixedThreadPool.submit(task));
}
newFixedThreadPool.shutdown();
for (Future<Date> future : list) {
System.out.println(future.get());// callable的不为空
}
}
}
old的解决方法
public class ThreadLocalTest {
private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");//每次都产生一个新的DateFormat解决线程安全问题
}
};
/**
* format:yyyy-MM-dd
*
* @param str
* @throws ParseException
* @return
*/
public static Date getDate(String str) throws ParseException{
return threadLocal.get().parse(str);
}
}
public class OldTimeTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return ThreadLocalTest.getDate("2018-5-5");
}
};
List<Future<Date>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(newFixedThreadPool.submit(task));
}
newFixedThreadPool.shutdown();
for (Future<Date> future : list) {
System.out.println(future.get());
}
}
}
新的时间api 使用ISO-8601标准
//DateTimeFormatter LocalDate
public class NewLocalDateTime {
public static void main(String[] args) throws InterruptedException, ExecutionException {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
Callable<LocalDate> task = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("2018-05-05", df);//格式需要完全一致"2018-5-5"就不行
}
};
List<Future<LocalDate>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(newFixedThreadPool.submit(task)) ;
}
for (Future<LocalDate> future : list) {
System.out.println(future.get());
}
newFixedThreadPool.shutdown();
}
}
//DateTimeFormatter LocalDate
public void main(String[] args) throws InterruptedException, ExecutionException {
Instant now = Instant.now();//默认使用 UTC 时区 +8h
System.out.println(now);//2018-08-05T07:23:22.110Z
OffsetDateTime atOffset = now.atOffset(ZoneOffset.ofHours(8));
long l = atOffset.toInstant().toEpochMilli();
System.out.println(atOffset);//2018-08-05T15:23:22.110+08:00
long epochMilli = now.toEpochMilli();
System.out.println(epochMilli);// System.currentTimeMillis() new Date().getTime()
System.out.println("----------------");
LocalDateTime localDateTime=LocalDateTime.now();//获取本地时间
DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy年MM月dd天hh时mm分ss秒");
String format = localDateTime.format(df);//
System.out.println(format);
System.out.println("----------------");
LocalDateTime parse = LocalDateTime.parse("2006年5月6日", df);
Instant oldTime = Instant.now();
Thread.sleep(1000);
Instant newTime = Instant.now();
Duration between = Duration.between(oldTime, newTime);
System.out.println(between.getSeconds());//1s
//Period.between(ld2, ld1); 年月天 时间差
//ZonedDate、ZonedTime、ZonedDateTime : 带时区的时间或日期
//LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
}

浙公网安备 33010602011771号