JDK8新特性

JDK8新特性

  • Lambda表达式
  • 方法引用
  • 函数式接口
  • 默认方法
  • Stream
  • Optional 类
  • Nashorn, JavaScript 引擎
  • 新的日期时间 API
  • Base64

Lambda表达式

在JDK8之前,Java是不支持函数式编程的,所谓的函数编程,即可理解是将一个函数(也称为“行为”)作为一个参数进行传递。通常我们提及得更多的是面向对象编程,面向对象编程是对数据的抽象(各种各样的POJO类),而函数式编程则是对行为的抽象(将行为作为一个参数进行传递)。

//before JDK8
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
});

//after JDK8
new Thread(() -> System.out.println("Hello World!"));
//相当于
Runnable r = () -> System.out.println("Hello World!");
Thread t =  new Thread(r);

在这个例子中,传统的语法规则,我们是将一个匿名内部类作为参数进行传递,我们实现了Runnable接口,并将其作为参数传递给Thread类,这实际上我们传递的是一段代码,也即我们将代码作为了数据进行传递,这就带来许多不必要的“样板代码”。

能够接收Lambda表达式的参数类型,是一个只包含一个方法的接口。只包含一个方法的接口称之为“函数接口”。Runnable接口只包含一个run()方法。
  
Lambda 表达式语法:
(parameters) -> expression

(parameters) ->{ statements; }

lambda表达式的重要特征:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

interface MathOperation {
//只包含一个方法的接口
    int operation(int a, int b);
}
interface GreetingService {
//只包含一个方法的接口
    void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation) {
    return mathOperation.operation(a, b);
}

public static void main(String args[]) {
    // 类型声明
    MathOperation addition = (int a, int b) -> a + b;
    // 不用类型声明
    MathOperation subtraction = (a, b) -> a - b;
    // 大括号中的返回语句
    MathOperation multiplication = (int a, int b) -> {
        return a * b;
    };
    // 没有大括号及返回语句
    MathOperation division = (int a, int b) -> a / b;

    // 不用括号
    GreetingService greetService1 = message ->
            System.out.println("Hello " + message);
    // 用括号
    GreetingService greetService2 = (message) ->
            System.out.println("Hello " + message);

    //直接调用lambda表达式
    greetService1.sayMessage("Hello");    
    //lambda表达式作为参数
    Temp tester = new Temp();
    System.out.println("10 / 5 = " + tester.operate(10, 5, division));
}

lambda 表达式变量作用域

  • lambda 表达式只能引用 final 修饰的外层局部变量,如果该外层局部变量不显式用final修饰,会自动隐性添加final语义。因此该变量不管在lambda表达式中或后面的代码中 都不可被改变。(Lambda可以引用成员变量,该成员变量可以不被final修饰,也可以改变,但最好不要这么做)
  • Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。
interface MathOperation {
    void operation(String s);
}

public static void main(String args[]) {
    final int i =2;//显式添加final修饰
    int j =3;//隐性添加final修饰
    MathOperation m = (String say) -> {
//            i=4; //编译出错,lambda表达式内不可被修改
//            j=5; //编译出错,lambda表达式内不可被修改
        System.out.println(say + String.valueOf((i+j)));
    };
    
//        MathOperation m2 = (int i) -> { //编译出错,lambda变量与局部变量同名
//            System.out.println(i);
//        };

//        i=4; //编译出错,lambda表达式外不可被修改
//        j=5; //编译出错,lambda表达式外不可被修改
    m.operation("Hello:");
}

参考:
https://www.cnblogs.com/yulinfeng/p/8452379.html
http://www.runoob.com/java/java8-lambda-expressions.html

方法引用

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。

方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::",但是有时候,我们的Lambda表达式可能仅仅调用一个已存在的方法,而不做任何其它事,对于这种情况,通过一个方法名字来引用这个已存在的方法会更加清晰,Java 8的方法引用允许我们这样做。方法引用是一个更加紧凑,易读的Lambda表达式。

import java.time.LocalDate;

public class Person {

    public Person(String name, LocalDate birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    String name;
    LocalDate birthday;
    public LocalDate getBirthday() {
        return birthday;
    }

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }

    @Override
    public String toString() {
        return this.name;
    }
}

public class testMethodReference {
    public void test() {
        Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};

        // 使用匿名类
        Arrays.sort(pArr, new Comparator<Person>() {
            @Override
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        });
        
        //使用lambda表达式
	    Arrays.sort(pArr, (Person a, Person b) -> {
	        return a.getBirthday().compareTo(b.getBirthday());
	    });        
    
	    //使用lambda表达式和类的静态方法
	    Arrays.sort(pArr, (a ,b) -> Person.compareByAge(a, b));
	    
	    //使用方法引用,引用的是类的静态方法
	    Arrays.sort(pArr, Person::compareByAge);
    
	    System.out.println(Arrays.asList(pArr));
	}
}

四种形式的方法引用:

类型 示例
引用静态方法 ContainingClass::staticMethodName
引用某个对象的实例方法 containingObject::instanceMethodName
引用某个类型的任意对象的实例方法 ContainingType::methodName
引用构造方法 ClassName::new

参考:https://www.cnblogs.com/xiaoxi/p/7099667.html

函数式接口

Java8的新引入,包含函数式的设计,接口都有@FunctionalInterface的注解(非必须)。就像这个注解的注释说明一样,它注解在接口层面,且注解的接口要有且仅有一个抽象方法。函数式接口可以被隐式转换为 lambda 表达式。示例见 Lambda表达式 小节中的MathOperation 、GreetingService 接口。

默认方法

之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口(新增抽象方法)时候,需要修改全部实现该接口的类。引进的默认方法,目的是为了解决接口的修改与现有的实现不兼容的问题。

interface FourWheeler {
    // 默认方法
    default void print(){
        System.out.println("我是一辆四轮车!");
    }
}

Java 8 的另一个特性是接口可以声明(并且可以提供实现)静态方法。

public interface Vehicle {
   // 默认方法
   default void print(){
      System.out.println("我是一辆车!");
   }
   
   // 静态方法
   static void blowHorn(){
      System.out.println("按喇叭!!!");
   }
}

具体实现类Car 可以不实现默认,也可以override默认方法。

class Car implements Vehicle, FourWheeler {
    public void print(){
        Vehicle.super.print();
        FourWheeler.super.print();
        Vehicle.blowHorn();
        System.out.println("我是一辆汽车!");
    }
}

参考:http://www.runoob.com/java/java8-default-methods.html

Stream

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

集合接口有两个方法来生成流:

  • stream() − 为集合创建串行流。
  • parallelStream() − 为集合创建并行流。parallelStream较stream速度快,但是要开放多线程和进行多线程间的切换,会消耗额外的资源,而且parallelStream()不是线程安全的。

格式:
| stream of elements ±----> |filter±> |sorted±> |map±> |collect|

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
strings.stream().filter(s -> !s.isEmpty()).sorted().limit(4).forEach(System.out::println);

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList()
squaresList.forEach(System.out::println););

//Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);

//统计
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());

参考:http://www.runoob.com/java/java8-streams.html

Optional 类

Optional常用方法:

//1.Optional.of()或者Optional.ofNullable():创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。
// 参数不能是null
Optional<Integer> optional1 = Optional.of(1); 
// 参数可以是null
Optional<Integer> optional2 = Optional.ofNullable(null); 
// 参数可以是非null
Optional<Integer> optional3 = Optional.ofNullable(2);

//2.Optional.empty():所有null包装成的Optional对象:
Optional<Integer> optional1 = Optional.ofNullable(null);
Optional<Integer> optional2 = Optional.ofNullable(null);
System.out.println(optional1 == optional2);// true
System.out.println(optional1 == Optional.<Integer>empty());// true 
Object o1 = Optional.<Integer>empty();
Object o2 = Optional.<String>empty();
System.out.println(o1 == o2);// true

//3.isPresent():判断值是否存在
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
 
//4. isPresent判断值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);

//5.ifPresent(Consumer consumer):如果option对象保存的值不是null,则调用consumer对象,否则不调用
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null); 
// 如果不是null,调用Consumer
optional1.ifPresent(new Consumer<Integer>() {
	@Override
	public void accept(Integer t) {
		System.out.println("value is " + t);
	}
}); 
// null,不调用Consumer
optional2.ifPresent(new Consumer<Integer>() {
	@Override
	public void accept(Integer t) {
		System.out.println("value is " + t);
	}
});

//6.orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
 
//7.orElse
System.out.println(optional1.orElse(1000) == 1);// true
System.out.println(optional2.orElse(1000) == 1000);// true

//8.orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个对象
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null); 
System.out.println(optional1.orElseGet(() -> {
	return 1000;
}) == 1);//true 
System.out.println(optional2.orElseGet(() -> {
	return 1000;
}) == 1000);//true

//9.orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似Guava的Precoditions
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null); 
optional1.orElseThrow(()->{throw new IllegalStateException();}); 
try
{
	// 抛出异常
	optional2.orElseThrow(()->{throw new IllegalStateException();});
}
catch(IllegalStateException e )
{
	e.printStackTrace();
}

//10.filter(Predicate):判断Optional对象中保存的值是否满足Predicate,并返回新的Optional。
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null); 
Optional<Integer> filter1 = optional1.filter((a) -> a == null);
Optional<Integer> filter2 = optional1.filter((a) -> a == 1);
Optional<Integer> filter3 = optional2.filter((a) -> a == null);
System.out.println(filter1.isPresent());// false
System.out.println(filter2.isPresent());// true
System.out.println(filter2.get().intValue() == 1);// true
System.out.println(filter3.isPresent());// false

//11.map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null); 
Optional<String> str1Optional = optional1.map((a) -> "key" + a);
Optional<String> str2Optional = optional2.map((a) -> "key" + a); 
System.out.println(str1Optional.get());// key1
System.out.println(str2Optional.isPresent());// false

//12.flatMap():功能与map()相似,差别请看如下代码。flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。
Optional<Integer> optional1 = Optional.ofNullable(1); 
Optional<Optional<String>> str1Optional = optional1.map((a) -> {
	return Optional.<String>of("key" + a);
}); 
Optional<String> str2Optional = optional1.flatMap((a) -> {
	return Optional.<String>of("key" + a);
}); 
System.out.println(str1Optional.get().get());// key1
System.out.println(str2Optional.get());// key1

如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了

Optional<User> user = ……
if (user.isPresent()) {
	return user.getOrders();
} else {
	return Collections.emptyList();
}

那么不得不说我们的思维仍然是在原地踏步, 只是本能的认为它不过是 User 实例的包装, 这与我们之前写成

User user =..
if (user != null) {
	return user.getOrders();
} else {
	return Collections.emptyList();
}

实质上是没有任何分别. 这就是我们将要讲到的使用好 Java 8 Optional 类型的正确姿势.

return user.orElse(null);  
return user.orElse(UNKNOWN_USER);
//而不是 return user.isPresent() ? user.get() : null;

return user.orElseGet(() -> fetchAUserFromDatabase()); 
//而不要 return user.isPresent() ? user: fetchAUserFromDatabase();

user.ifPresent(System.out::println); 
//而不要下边那样
if (user.isPresent()) {
  System.out.println(user.get());
}

return user.map(u -> u.getOrders()).orElse(Collections.emptyList()) 
//而不要
if(user.isPresent()) {
  return user.get().getOrders();
} else {
  return Collections.emptyList();
}


//map是可能无限级联的, 比如再深一层, 获得用户名的大写形式
return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);
           
//以前, 每一级调用的展开都需要放一个 null 值的判断
User user = .....
if(user != null) {
  String name = user.getUsername();
  if(name != null) {
    return name.toUpperCase();
  } else {
    return null;
  }
} else {
  return null;
}

参考:
https://blog.csdn.net/aitangyong/article/details/54564100#
http://www.importnew.com/22060.html

Nashorn, JavaScript 引擎

  1. Java中调用JavaScript
//script.js文件
var fun1 = function(name) {
    print('Hi there from Javascript, ' + name);
    return "greetings from javascript";
};

var fun2 = function (object) {
    print("JS Class Definition: " + Object.prototype.toString.call(object));
};
//java中直接调用js函数
public void test1() throws ScriptException {                                   
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    engine.eval("print('Hello World!');");                                     
}     
  
//java中调用js文件中的自定义的函数
public void test3() throws Exception {                                         
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    engine.eval(new FileReader("script.js"));                                  

    Invocable invocable = (Invocable) engine;                                  

    Object result = invocable.invokeFunction("fun1", "Peter Parker");          
    System.out.println(result);                                                
    System.out.println(result.getClass());                                     

    // Hi there from Javascript, Peter Parker                                  
    // greetings from javascript                                               
    // class java.lang.String     
    
    invocable.invokeFunction("fun2", new Date());
}                                                                                                                
  1. JavaScript中调用Java
//定义一个静态的 Java 方法
static String fun1(String name) {
    System.out.format("Hi there from Java, %s", name);
    return "greetings from java";
}
//JavaScript 可通过 Java.type API 来引用 Java 类。
var MyJavaClass = Java.type('my.package.MyJavaClass');
var result = MyJavaClass.fun1('John Doe');
print(result);

// Hi there from Java, John Doe
// greetings from java

参考:https://blog.csdn.net/liupeifeng3514/article/details/80722880

新的日期时间 API

在java8以前, 当你在做有关时间日期的操作时,你会想到用Date; 当你在做日期、月份、天数相加减时,你会想到用Calendar;当你需要对时间日期进行格式化时,你会想到使用SimpleDateFormat或DateFormat下的其他子类;但是,以上有关的时间日期操作对象,都是可变的、线程不安全的,同时,如果作为一个经常写过类似代码的人来说,尽管有相关对象提供某些操作,但并不能很快、很简单的就能得到最终想要的结果,java8出的新的时间日期API都是线程安全的,并且性能更好代码更简洁

ZoneId: 时区ID,用来确定Instant和LocalDateTime互相转换的规则
Instant: 用来表示时间线上的一个点(瞬时)
LocalDate: 表示没有时区的日期, LocalDate是不可变并且线程安全的
LocalTime: 表示没有时区的时间, LocalTime是不可变并且线程安全的
LocalDateTime: 表示没有时区的日期时间, LocalDateTime是不可变并且线程安全的
Clock: 用于访问当前时刻、日期、时间,用到时区
Duration: 用秒和纳秒表示时间的数量(长短),用于计算两个日期的“时间”间隔
Period: 用于计算两个“日期”间隔

//(1) 获取当前时间
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);

//(2) 根据指定日期/时间创建对象
LocalDate localDate = LocalDate.of(2018, 1, 13);
LocalTime localTime = LocalTime.of(9, 43, 20);
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 13, 9, 43, 20);
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);

//(3) 日期时间的加减
LocalDateTime localDateTime = LocalDateTime.now();
//以下方法的参数都是long型,返回值都是LocalDateTime
LocalDateTime plusYearsResult = localDateTime.plusYears(2L);
LocalDateTime plusMonthsResult = localDateTime.plusMonths(3L);
LocalDateTime plusDaysResult = localDateTime.plusDays(7L);
LocalDateTime plusHoursResult = localDateTime.plusHours(2L);
LocalDateTime plusMinutesResult = localDateTime.plusMinutes(10L);
LocalDateTime plusSecondsResult = localDateTime.plusSeconds(10L);
		
System.out.println("当前时间是 : " + localDateTime + "\n"
		+ "当前时间加2年后为 : " + plusYearsResult + "\n"
		+ "当前时间加3个月后为 : " + plusMonthsResult + "\n"
		+ "当前时间加7日后为 : " + plusDaysResult + "\n"
		+ "当前时间加2小时后为 : " + plusHoursResult + "\n"
		+ "当前时间加10分钟后为 : " + plusMinutesResult + "\n"
		+ "当前时间加10秒后为 : " + plusSecondsResult + "\n"
		);
		
//也可以以另一种方式来相加减日期,即plus(long amountToAdd, TemporalUnit unit)
//参数1 : 相加的数量, 参数2 : 相加的单位
LocalDateTime nextMonth = localDateTime.plus(1, ChronoUnit.MONTHS);
LocalDateTime nextYear = localDateTime.plus(1, ChronoUnit.YEARS);
LocalDateTime nextWeek = localDateTime.plus(1, ChronoUnit.WEEKS);
		
System.out.println("now : " + localDateTime + "\n"
		+ "nextYear : " + nextYear + "\n"
		+ "nextMonth : " + nextMonth + "\n"
		+ "nextWeek :" + nextWeek + "\n"
		);
		
//(4) 将年、月、日等修改为指定的值,并返回新的日期(时间)对象
LocalDate localDate = LocalDate.now();
//当前时间基础上,指定本年当中的第几天,取值范围为1-365,366
LocalDate withDayOfYearResult = localDate.withDayOfYear(200);
//当前时间基础上,指定本月当中的第几天,取值范围为1-29,30,31
LocalDate withDayOfMonthResult = localDate.withDayOfMonth(5);
//当前时间基础上,直接指定年份
LocalDate withYearResult = localDate.withYear(2017);
//当前时间基础上,直接指定月份
LocalDate withMonthResult = localDate.withMonth(5);
System.out.println("当前时间是 : " + localDate + "\n"
		+ "指定本年当中的第200天 : " + withDayOfYearResult + "\n"
		+ "指定本月当中的第5天 : " + withDayOfMonthResult + "\n"
		+ "直接指定年份为2017 : " + withYearResult + "\n"
		+ "直接指定月份为5月 : " + withMonthResult + "\n"
		);

//(5) 获取日期的年月日周时分秒
LocalDateTime localDateTime = LocalDateTime.now();
int dayOfYear = localDateTime.getDayOfYear();
int dayOfMonth = localDateTime.getDayOfMonth();
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
System.out.println("今天是" + localDateTime + "\n"
		+ "本年当中第" + dayOfYear + "天" + "\n"
		+ "本月当中第" + dayOfMonth + "天" + "\n"
		+ "本周中星期" + dayOfWeek.getValue() + "-即" + dayOfWeek + "\n");
		
//获取当天时间的年月日时分秒
int year = localDateTime.getYear();
Month month = localDateTime.getMonth();
int day = localDateTime.getDayOfMonth();
int hour = localDateTime.getHour();
int minute = localDateTime.getMinute();
int second = localDateTime.getSecond();
System.out.println("今天是" + localDateTime + "\n"
		+ "年 : " + year + "\n"
		+ "月 : " + month.getValue() + "-即 "+ month + "\n"
		+ "日 : " + day + "\n"
		+ "时 : " + hour + "\n"
		+ "分 : " + minute + "\n"
		+ "秒 : " + second + "\n"
		);

//(6) 时间日期前后的比较与判断
//判断两个时间点的前后
LocalDate localDate1 = LocalDate.of(2017, 8, 8);
LocalDate localDate2 = LocalDate.of(2018, 8, 8);
boolean date1IsBeforeDate2 = localDate1.isBefore(localDate2);
System.out.println("date1IsBeforeDate2 : " + date1IsBeforeDate2);

//(7) 判断是否为闰年
LocalDate now = LocalDate.now();
System.out.println("now : " + now + ", is leap year ? " + now.isLeapYear());

//(8) java8时钟 : clock()
//返回当前时间,根据系统时间和UTC
Clock clock = Clock.systemUTC();
System.out.println(clock);

//(9) 时间戳
Instant instant = Instant.now();
System.out.println(instant);
Date date = Date.from(instant);
Instant instant2 = date.toInstant();
System.out.println(date);
System.out.println(instant2);

//(10) 计算时间、日期间隔
//计算两个日期的日期间隔-年月日
LocalDate date1 = LocalDate.of(2018, 2, 13);
LocalDate date2 = LocalDate.of(2017, 3, 12);
//内部是用date2-date1,所以得到的结果是负数
Period period = Period.between(date1, date2);
System.out.println("相差年数 : " + period.getYears());
System.out.println("相差月数 : " + period.getMonths());
System.out.println("相差日数 : " + period.getDays());
//还可以这样获取相差的年月日
System.out.println("-------------------------------");
long years = period.get(ChronoUnit.YEARS);
long months = period.get(ChronoUnit.MONTHS);
long days = period.get(ChronoUnit.DAYS);
System.out.println("相差的年月日分别为 : " + years + "," + months + "," + days);
//注意,当获取两个日期的间隔时,并不是单纯的年月日对应的数字相加减,而是会先算出具体差多少天,在折算成相差几年几月几日的
		
//计算两个时间的间隔
System.out.println("-------------------------------");
LocalDateTime date3 = LocalDateTime.now();
LocalDateTime date4 = LocalDateTime.of(2018, 1, 13, 22, 30, 10);
Duration duration = Duration.between(date3, date4);
System.out.println(date3 + " 与 " + date4 + " 间隔  " + "\n"
		+ " 天 :" + duration.toDays() + "\n"
		+ " 时 :" + duration.toHours() + "\n"
		+ " 分 :" + duration.toMinutes() + "\n"
		+ " 毫秒 :" + duration.toMillis() + "\n"
		+ " 纳秒 :" + duration.toNanos() + "\n"
		);
		
//(11) 当计算程序的运行时间时,应当使用时间戳Instant
Instant ins1 = Instant.now();
for (int i = 0; i < 10000000; i++) {
			//循环一百万次
}
Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1, ins2);
System.out.println("程序运行耗时为 : " + duration.toMillis() + "毫秒");

//(12) 时间日期的格式化(格式化后返回的类型是String)
//使用jdk自身配置好的日期格式
DateTimeFormatter formatter1 = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime date1 = LocalDateTime.now();
//反过来调用也可以 : date1.format(formatter1);
String date1Str = formatter1.format(date1);
System.out.println(date1Str);

//使用自定义格式
LocalDateTime date1 = LocalDateTime.now();
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String date2Str = formatter2.format(date1);
System.out.println(date2Str);

//将时间字符串形式转化为日期对象
String datetime =  "2018-01-13 21:27:30";  
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse(datetime, dtf);  
System.out.println(ldt);  

//long毫秒值转换为日期
System.out.println("---------long毫秒值转换为日期---------");
DateTimeFormatter df= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String longToDateTime = df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));
System.out.println(longToDateTime);

参考:https://blog.csdn.net/h_xiao_x/article/details/79729507

Base64

//jdk8 编码
String asB64 ="";
try {
    asB64 = Base64.getEncoder().encodeToString("测试文本".getBytes("utf-8"));
    System.out.println(asB64);
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

//jdk8 解码
byte[] asBytes = Base64.getDecoder().decode(asB64);
try {
    System.out.println(new String(asBytes, "utf-8"));
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

//jdk7 base64编码
import sun.misc.BASE64Encoder;
public class TestBase64JDK7 {
    private static final String TEST_STRING = "0123456789,0123456789,0123456789,0123456789,0123456789,0123456789,0123456789";
    public static void main(String[] args) {
        BASE64Encoder base64Encoder = new BASE64Encoder();
        String base64Result = base64Encoder.encode(TEST_STRING.getBytes());
        System.out.println(base64Result);
    }
}
//使用jdk7编码,jdk8进行解码可能会IllegalArgumentException。因为jdk7的base64编码允许包含换行符,而jdk8不允许。

参考:https://blog.csdn.net/java_4_ever/article/details/80978089

你可能感兴趣的:(Java)