java8 新特性精心整理(全)

前言

愈來愈多的項目已經使用 Java 8 了,毫無疑問,Java 8 是Java自Java 5(發佈於2004年)以後的最重要的版本。這個版本包含語言、編譯器、庫、工具和 JVM 等方面的十多個新特性。在本文中咱們將學習這些新特性,並用實際的例子說明在什麼場景下適合使用。html

引用:本文參考了這兩篇文章,加以本身的理解,整理成一份最容易理解的 Java8 新特性文章,有少部分章節可能內容一致,但絕對不是抄襲,只是爲了文章的完整性,大部分經常使用的地方加了我本身的理解和示例。java

http://www.javashuo.com/article/p-rtcgnvtk-a.htmlgit

https://blog.csdn.net/maosijunzi/article/details/38658095spring

適合讀者及目標

目標人羣

  • 適合有用過 lambda 表達式的同窗,想完全瞭解清楚
  • 學習 Java8 的新特定

目標

  • 瞭解 java8 的函數式接口和 Lambda 表達式
  • 方法引用的使用
  • 接口的靜態方法和默認方法
  • Date/Time Api 的使用
  • Stream API 的使用

1. Java 語言的新特性

Java8 的 lambda 的使用確實方便了許多,但也使初次瞭解的人感受到難以閱讀,實際上是你不習慣的緣由。不少語言從一開始就支持了 Lambda 表達式,像 Groovy,Scala 等。數據庫

1.1 Lambda 表達式和函數式接口

在 Java8 之前,咱們想要讓一個方法能夠與用戶進行交互,好比說使用方法內的局部變量;這時候就只能使用接口作爲參數,讓用戶實現這個接口或使用匿名內部類的形式,把局部變量經過接口方法傳給用戶。apache

傳統匿名內部類缺點:代碼臃腫,難以閱讀編程

Lambda 表達式

Lambda 表達式將函數當成參數傳遞給某個方法,或者把代碼自己看成數據處理;api

語法格式:併發

  • 用逗號分隔的參數列表
  • -> 符號
  • 和 語句塊 組成
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

等價於oracle

List<String> list = Arrays.asList( "a", "b", "d" );
for(String e:list){
    System.out.println(e);
}

若是語句塊比較複雜,使用 {} 包起來

Arrays.asList( "a", "b", "d" ).forEach( e -> {
    String m = "9420 "+e;
    System.out.print( m );
});

Lambda 本質上是匿名內部類的改裝,因此它使用到的變量都會隱式的轉成 final

String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( 
    e -> System.out.print( e + separator ) );

等價於

final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( 
    e -> System.out.print( e + separator ) );

Lambda 的返回值和參數類型由編譯器推理得出,不須要顯示定義,若是隻有一行代碼能夠不寫 return 語句

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

等價於

List<String> list = Arrays.asList("a", "b", "c");
Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});

函數式接口

  • 接口中只能有一個接口方法
  • 能夠有靜態方法和默認方法
  • 使用 @FunctionalInterface 標記
  • 默認方法能夠被覆寫
@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();
 
    default void defaultMethod() {            
    }
    
    static void staticMethod(){
    }
}
private interface Defaulable {
    // Interfaces now allow default methods, the implementer may or 
    // may not implement (override) them.
    default String notRequired() { 
        return "Default implementation"; 
    }        
}
 
private static class DefaultableImpl implements Defaulable {
}
 
private static class OverridableImpl implements Defaulable {
    @Override
    public String notRequired() {
        return "Overridden implementation";
    }
}

// 也能夠由接口覆蓋 
public interface OverridableInterface extends Defaulable{
    @Override
    public String notRequired() {
        return "interface Overridden implementation";
    }
}

因爲JVM上的默認方法的實如今字節碼層面提供了支持,所以效率很是高。默認方法容許在不打破現有繼承體系的基礎上改進接口。該特性在官方庫中的應用是:給 java.util.Collection接口添加新方法,如 stream()parallelStream()forEach()removeIf() 等等。

已經存在的 Java8 定義的函數式接口

咱們基本不須要定義本身的函數式接口,Java8 已經給咱們提供了大量的默認函數式接口,基本夠用,在 rt.jar 包的 java.util.function 目錄下能夠看到全部默認的函數式接口,大體分爲幾類

  • Function<T,R> T 做爲輸入,返回的 R 做爲輸出
  • Predicate<T> T 做爲輸入 ,返回 boolean 值的輸出
  • Consumer<T> T 做爲輸入 ,沒有輸出
  • Supplier<R> 沒有輸入 , R 做爲輸出
  • BinaryOperator<T> 兩個 T 做爲輸入 ,T 一樣是輸出
  • UnaryOperator<T>Function 的變種 ,輸入輸出者是 T

其它的都是上面幾種的各類擴展,只爲更方便的使用,下面演示示例,你能夠把其當成正常的接口使用,由用戶使用 Lambda 傳入。

// hello world 示例
Function<String,String> function = (x) -> {return x+"Function";};
System.out.println(function.apply("hello world"));    // hello world Function

UnaryOperator<String> unaryOperator = x -> x + 2;
System.out.println(unaryOperator.apply("9420-"));    // 9420-2

// 判斷輸入值是否爲偶數示例
Predicate<Integer> predicate = (x) ->{return x % 2 == 0 ;};
System.out.println(predicate.test(1));                // false

// 這個沒有返回值
Consumer<String> consumer = (x) -> {System.out.println(x);};
consumer.accept("hello world ");                    // hello world

// 這個沒有輸入 
Supplier<String> supplier = () -> {return "Supplier";};
System.out.println(supplier.get());                    // Supplier

// 找出大數
BinaryOperator<Integer> bina = (x, y) ->{return x > y ? x : y;};
bina.apply(1,2);                                    // 2

1.2 方法引用

方法引用使得開發者能夠直接引用現存的方法、Java類的構造方法或者實例對象。方法引用和Lambda表達式配合使用,使得java類的構造方法看起來緊湊而簡潔,沒有不少複雜的模板代碼。

public static class Car {
    public static Car create( final Supplier< Car > supplier ) {
        return supplier.get();
    }              
 
    public static void collide( final Car car ) {
        System.out.println( "Collided " + car.toString() );
    }
 
    public void follow( final Car another ) {
        System.out.println( "Following the " + another.toString() );
    }
 
    public void repair() {   
        System.out.println( "Repaired " + this.toString() );
    }
}

第一種方法引用的類型是構造器引用,語法是Class::new,或者更通常的形式:Class<T>::new。注意:這個構造器沒有參數。

final Car car = Car.create( Car::new );

等價於

Car car = Car.create(() -> new Car());

第二種方法引用的類型是靜態方法引用,語法是Class::static_method。注意:這個方法接受一個Car類型的參數。

cars.forEach( Car::collide );

forEach 原型爲 forEach(Consumer<? super T> action) 使用的是 Consumer 只有參數,沒有返回值;這個參數 T 就是 car 類型,由於是 cars.forEach 嘛,因此上面的方法引用等價於

cars.forEach(car -> Car.collide(car));

第三種方法引用的類型是某個類的成員方法的引用,語法是Class::method,注意,這個方法沒有定義入參:

cars.forEach( Car::repair );

它等價於

cars.forEach(car -> car.repair());

1.3 重複註解

自從Java 5中引入註解以來,這個特性開始變得很是流行,並在各個框架和項目中被普遍使用。不過,註解有一個很大的限制是:在同一個地方不能屢次使用同一個註解。Java 8打破了這個限制,引入了重複註解的概念,容許在同一個地方屢次使用同一個註解。

在Java 8中使用 @Repeatable 註解定義重複註解,實際上,這並非語言層面的改進,而是編譯器作的一個trick,底層的技術仍然相同。能夠利用下面的代碼說明:

@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
@Repeatable( Filters.class )
public @interface Filter {
    String value();
};

@Filter( "filter1" )
@Filter( "filter2" )
public interface Filterable {        
}

public static void main(String[] args) {
    for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
        System.out.println( filter.value() );
    }
}

正如咱們所見,這裏的Filter類使用 @Repeatable(Filters.class) 註解修飾,而Filters是存放Filter註解的容器,編譯器儘可能對開發者屏蔽這些細節。這樣,Filterable接口能夠用兩個Filter註解註釋(這裏並無提到任何關於Filters的信息)。

另外,反射API提供了一個新的方法:getAnnotationsByType(),能夠返回某個類型的重複註解,例如Filterable.class.getAnnoation(Filters.class)將返回兩個Filter實例。

1.4 更好的類型推斷

Java 8編譯器在類型推斷方面有很大的提高,在不少場景下編譯器能夠推導出某個參數的數據類型,從而使得代碼更爲簡潔。例子代碼以下:

public class Value< T > {
    public static< T > T defaultValue() { 
        return null; 
    }
 
    public T getOrDefault( T value, T defaultValue ) {
        return ( value != null ) ? value : defaultValue;
    }
}
public class TypeInference {
    public static void main(String[] args) {
        final Value< String > value = new Value<>();
        value.getOrDefault( "22", Value.defaultValue() );
    }
}

參數 Value.defaultValue() 的類型由編譯器推導得出,不須要顯式指明。在Java 7中這段代碼會有編譯錯誤,除非使用Value.<String>defaultValue()

1.5 拓寬註解的應用場景

Java 8拓寬了註解的應用場景。如今,註解幾乎可使用在任何元素上:局部變量、接口類型、超類和接口實現類,甚至能夠用在函數的異常定義上。下面是一些例子:

package com.javacodegeeks.java8.annotations;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;
 
public class Annotations {
    @Retention( RetentionPolicy.RUNTIME )
    @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
    public @interface NonEmpty {        
    }
 
    public static class Holder< @NonEmpty T > extends @NonEmpty Object {
        public void method() throws @NonEmpty Exception {            
        }
    }
 
    @SuppressWarnings( "unused" )
    public static void main(String[] args) {
        final Holder< String > holder = new @NonEmpty Holder< String >();        
        @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();        
    }
}

ElementType.TYPE_USER ElementType.TYPE_PARAMETER 是Java 8新增的兩個註解,用於描述註解的使用場景。Java 語言也作了對應的改變,以識別這些新增的註解。

2. Java 編譯器的新特性

Java 8 開始正式支持參數名稱,終於不須要讀 class 字節碼來獲取參數名稱了,這對於常用反射的人特別有用。

在 Java8 這個特性默認是關閉的,須要開啓參數才能獲取參數名稱:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
        <compilerArgument>-parameters</compilerArgument>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

3. JVM 的新特性

使用MetaspaceJEP 122)代替持久代(PermGen space)。在JVM參數方面,使用-XX:MetaSpaceSize-XX:MaxMetaspaceSize代替原來的-XX:PermSize-XX:MaxPermSize

4. Java 官方庫的新特性

Java 8增長了不少新的工具類(date/time類),並擴展了現存的工具類,以支持現代的併發編程、函數式編程等,本章節參考原文,並提取出經常使用功能。

4.1 Streams

Streams 操做分爲中間操做和晚期操做,中間操做會返回一個新的 Stream ,只是把要作的操做記錄起來而已,並不會真的執行,晚期操做纔會真的遍歷列表並執行全部操做

Stream 的另外一個價值就是支持了並行處理 parallel 方法。

Stream API 簡化了集合的操做,並擴展了集合的分組,求和,mapReduce,flatMap ,排序等功能,下面列出項目中常常用到的功能,會以使用頻率排序。

  1. 準備一個用於下面例子測試的對象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Vehicle {
    //車架號
    private String vin;
    // 車主手機號
    private String phone;
    // 車主姓名
    private String name;
    // 所屬車租車公司
    private Integer companyId;
    // 我的評分
    private Double score;
    //安裝的設備列表imei,使用逗號分隔
    private String deviceNos;
}
  1. 準備一些車輛數據
static List<Vehicle> vehicles = new ArrayList<>();

@Before
public void init(){
    List<String> imeis = new ArrayList<>();
    for (int i = 0; i <5 ; i++) {
        List<String> singleVehicleDevices = new ArrayList<>();
        for (int j = 0; j < 3; j++) {
            String imei = RandomStringUtils.randomAlphanumeric(15);
            singleVehicleDevices.add(imei);
        }
        imeis.add(StringUtils.join(singleVehicleDevices,','));
    }
    vehicles.add(new Vehicle("KPTSOA1K67P081452","17620411498","9420",1,4.5,imeis.get(0)));
    vehicles.add(new Vehicle("KPTCOB1K18P057071","15073030945","張玲",2,1.4,imeis.get(1)));
    vehicles.add(new Vehicle("KPTS0A1K87P080237","19645871598","sanri1993",1,3.0,imeis.get(2)));
    vehicles.add(new Vehicle("KNAJC526975740490","15879146974","李種",1,3.9,imeis.get(3)));
    vehicles.add(new Vehicle("KNAJC521395884849","13520184976","袁紹",2,4.9,imeis.get(4)));
}

4.1.1 forEach 遍歷Collection 數據

vehicles.forEach(vehicle -> System.out.println(vehicle));

//這樣就能夠遍歷打印
vehicles.forEach(System.out::println);

4.1.2 forEach 遍歷 Map 數據

Map<String,Integer> map = new HashMap<>();
map.put("a",1);map.put("b",2);map.put("c",3);

map.forEach((k,v) -> System.out.println("key:"+k+",value:"+v));

4.1.3 filter 數據過濾

// 去掉評分爲 3 分如下的車
List<Vehicle> collect = vehicles.stream().filter(vehicle -> vehicle.getScore() >= 3).collect(Collectors.toList());

4.1.4 map 對象映射

對一個 List<Object> 大部分狀況下,咱們只須要列表中的某一列,或者須要把裏面的每個對象轉換成其它的對象,這時候可使用 map 映射,示例:

// 取出全部的車架號列表
 List<String> vins = vehicles.stream().map(Vehicle::getVin).collect(Collectors.toList());

4.1.5 groupBy 按照某個屬性進行分組

// 按照公司 Id 進行分組
Map<Integer, List<Vehicle>> companyVehicles = vehicles.stream().collect(Collectors.groupingBy(Vehicle::getCompanyId));

// 按照公司分組求司機打分和
Map<Integer, Double> collect = vehicles.stream().collect(Collectors.groupingBy(Vehicle::getCompanyId, Collectors.summingDouble(Vehicle::getScore)));

4.1.6 sort 按照某個屬性排序 ,及多列排序

// 單列排序 
vehicles.sort((v1,v2) -> v2.getScore().compareTo(v1.getScore()));

// 或使用 Comparator 類來構建比較器,流處理不會改變原列表,須要接收返回值才能獲得預期結果
 List<Vehicle> collect = vehicles.stream().sorted(Comparator.comparing(Vehicle::getScore).reversed()).collect(Collectors.toList());

// 多列排序,score 降序,companyId 升序排列
List<Vehicle> collect = vehicles.stream().sorted(Comparator.comparing(Vehicle::getScore).reversed()
                .thenComparing(Comparator.comparing(Vehicle::getCompanyId)))
                .collect(Collectors.toList());

4.1.7 flatMap 扁平化數據處理

// 查出全部車綁定的全部設備
List<String> collect = vehicles.stream().map(vehicle -> {
    String deviceNos = vehicle.getDeviceNos();
    return StringUtils.split(deviceNos,',');
}).flatMap(Arrays::stream).collect(Collectors.toList());

flatMap 很適合 List<List>List<object []> 這種結構,能夠當成一個列表來處理;像上面的設備列表,在數據庫中存儲的結構就是以逗號分隔的數據,而車輛列表又是一個列表數據。

4.1.8 mapReduce 數據處理

// 對全部司機的總分求和
Double reduce = vehicles.stream().parallel().map(Vehicle::getScore).reduce(0d, Double::sum);

4.1.9 綜合處理示例

// 總的分值
Double totalScore = vehicles.stream().parallel().map(Vehicle::getScore).reduce(0d, Double::sum);

// 查看每個司機佔的分值比重
List<String> collect = vehicles.stream()
    .mapToDouble(vehicle -> vehicle.getScore() / totalScore)
    .mapToLong(weight -> (long) (weight * 100))
    .mapToObj(percentage -> percentage + "%")
    .collect(Collectors.toList());

原文的 boxed 不知道是什麼意思,但願有大神能幫忙解答下,不用 boxed 也是能夠的

4.2 Optional

Optional 用來解決 Java 中常常出現的 NullPointerException ,從而避免源碼被各類空檢查污染,使源碼更加簡潔和更加容易閱讀

// 假設有一個對象 obj ,你不知道它是否是爲空的,可是你想用它的方法,能夠這麼玩
Optional<T> canUseObj = Optional.ofNullable(obj);
canUseObj.ifPresent(System.out::println);        //若是 obj 不爲空,則可使用 obj 的方法,這裏作個簡單輸出

4.3 Date/Time API(JSR 310)

新的日期時間工具所有都在 java.time 及其子包中。

4.3.1 新 Date/Time API 設計原則

Java 8日期/時間API是 JSR-310 規範的實現,它的目標是克服舊的日期/時間API實現中全部的缺陷,新的日期/時間API的一些設計原則以下:

  • 不變性:新的日期/時間API中,全部的類都是不可變的,這種設計有利於併發編程。
  • 關注點分離:新的API將人可讀的日期時間和機器時間(unix timestamp)明確分離,它爲日期(Date)、時間(Time)、日期時間(DateTime)、時間戳(unix timestamp)以及時區定義了不一樣的類。
  • 清晰:在全部的類中,方法都被明肯定義用以完成相同的行爲。舉個例子,要拿到當前實例咱們可使用now()方法,在全部的類中都定義了format()和parse()方法,而不是像之前那樣專門有一個獨立的類。爲了更好的處理問題,全部的類都使用了工廠模式和策略模式,一旦你使用了其中某個類的方法,與其餘類協同工做並不困難。
  • 實用操做:全部新的日期/時間API類都實現了一系列方法用以完成通用的任務,如:加、減、格式化、解析、從日期/時間中提取單獨部分等操做。
  • 可擴展性:新的日期/時間API是工做在ISO-8601日曆系統上的,但咱們也能夠將其應用在非IOS的日曆上。

4.3.2 經常使用類及其使用

時間大體能夠分爲三個部分:日期、時間、時區

其中日期又細分爲年、月、日;時間又細分爲時、分、秒

通常機器時間用從 1970-01-01T00:00 到如今的秒數來表示時間; 這裏糾正大部分人犯的一個錯誤概念,時間戳指的是秒數,而不是毫秒數。

幾乎全部的時間對象都實現了 Temporal 接口,因此接口參數通常都是 Temporal

  • Instant: 表示時間線上的一個點,參考點是標準的Java紀元(epoch),即1970-01-01T00:00:00Z(1970年1月1日00:00 GMT)
  • LocalDate: 日期值對象如 2019-09-22
  • LocalTime:時間值對象如 21:25:36
  • LocalDateTime:日期+時間值對象
  • ZoneId:時區
  • ZonedDateTime:日期+時間+時區值對象
  • DateTimeFormatter:用於日期時間的格式化
  • Period:用於計算日期間隔
  • Duration:用於計算時間間隔
4.3.2.1 Instant 表示時間線上的一個點(瞬時)
// 測試執行一個 new 操做使用的時間(納秒值)
Instant begin = Instant.now();
StreamMain streamMain = new StreamMain();
Instant end = Instant.now();
System.out.println(Duration.between(begin,end).toNanos());
4.3.2.2 LocalDateLocalTimeLocalDateTimeZonedDateTime 能夠規爲一組,用於表示時間的
// 可使用 of 方法構建它們的實例,以下面建立了一個 2019-9-22 21:42:59 東八區 的時間對象 
LocalDate localDate = LocalDate.of(2019, Month.SEPTEMBER, 22);
LocalTime localTime = LocalTime.of(21, 42, 59);
LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());

// 獲取如今的時間,這是一個靜態方法
LocalDate now = LocalDate.now();

// 每一個實例能夠獲取它們的 part 信息,如獲取年 
int year = localDate.getYear();

// 能夠修改 part 信息,這將返回一個新對象,如增長一年
LocalDate localDatePlus = localDate.plusYears(1);

// 設置 part 信息,也會返回新的對象,如設置爲 2017 年 
LocalDate localDateWithYear = localDate.withYear(2017);

// 比較兩個日期 isAfter,isBefore
boolean after = localDate.isAfter(LocalDate.now());

// 格式化日期時間
// yyyy-MM-dd
System.out.println(now.format(DateTimeFormatter.ISO_DATE));
// yyyy-MM-ddTHH:mm:ss
System.out.println(now.format(DateTimeFormatter.ISO_DATE_TIME));
// yyyy-MM-dd HH:mm:ss
System.out.println(now.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));

// 日期解析 
System.out.println(LocalDate.parse("2019-09-22"));
System.out.println(LocalDateTime.parse("2019-09-22T21:05:22"));
System.out.println(LocalDateTime.parse("2019-09-22 21:05:22",DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
4.3.2.3 ZoneId 用來操做時區,它提供了獲取全部時區和本地時區的方法
ZoneId zoneId = ZoneId.systemDefault();
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
4.3.2.4 PeriodDuration 能夠視爲一組,用於計算時間間隔
// 建立一個兩週的間隔
Period periodWeeks = Period.ofWeeks(2);

// 一年三個月零二天的間隔
Period custom = Period.of(1, 3, 2);

// 一天的時長
Duration duration = Duration.ofDays(1);

// 計算2015/6/16 號到如今 2019/09/22 過了多久,它這個把間隔分到每一個 part 了
LocalDate now = LocalDate.now();
LocalDate customDate = LocalDate.of(2015, 6, 16);
Period between = Period.between(customDate, now);
// 結果爲 4:3:6 即過去了 4年3個月6天了
System.out.println(between.getYears()+":"+between.getMonths()+":"+between.getDays());

// 比較兩個瞬時的時間間隔 
Instant begin = Instant.now();
Instant end = Instant.now();
Duration.between(begin,end);

// 一樣能夠修改 part 信息和設置 part 信息,都是返回新的對象來表示設置過的值,原來的對象不變
Period plusDays = between.plusDays(1);
Period withDays = between.withDays(4);

4.3.3 與 Date,Calendar 的轉換

雖說,這個新的時間工具很好用,但若是不能與之前的舊的 api 兼容的話,同樣是沒有用的;還好新的工具類能很好的與之前的工具類進行相互轉換。

經過 Instant作中間轉換實現DateCalendarLocalDateTimeZonedDateTimeLocalDate 的互相轉換

// LocalDateTime 轉 Date
Date localDateTimeDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
// LocalDateTime 轉 Calendar
Calendar localDateTimeCalendar = GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault()));

// Date 轉 LocalDateTime
LocalDateTime dateLocalDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
// Calendar 轉 LocalDateTime
LocalDateTime calendarLocalDateTime = LocalDateTime.ofInstant(calendar.toInstant(), ZoneOffset.systemDefault());

4.4 Base64

對於 Base64 終於不用引用第三方包了,使用 java 庫就能夠完成

// 編碼
final String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
// 解碼
final String decoded = new String( Base64.getDecoder().decode( encoded ),StandardCharsets.UTF_8 );

4.5 JUC 工具包擴充

基於新增的lambda表達式和steam特性,爲Java 8中爲java.util.concurrent.ConcurrentHashMap類添加了新的方法來支持聚焦操做;另外,也爲java.util.concurrentForkJoinPool類添加了新的方法來支持通用線程池操做(更多內容能夠參考咱們的併發編程課程)。

Java 8還添加了新的java.util.concurrent.locks.StampedLock類,用於支持基於容量的鎖——該鎖有三個模型用於支持讀寫操做(能夠把這個鎖當作是java.util.concurrent.locks.ReadWriteLock的替代者)。

java.util.concurrent.atomic包中也新增了很多工具類,列舉以下:

  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

5. 新的工具

Java 8提供了一些新的命令行工具,這部分會講解一些對開發者最有用的工具。

5.1 類依賴分析器:jdeps

deps是一個至關棒的命令行工具,它能夠展現包層級和類層級的Java類依賴關係,它以.class文件、目錄或者Jar文件爲輸入,而後會把依賴關係輸出到控制檯。

咱們能夠利用jedps分析下Spring Framework庫,爲了讓結果少一點,僅僅分析一個JAR文件:org.springframework.core-3.0.5.RELEASE.jar

jdeps org.springframework.core-3.0.5.RELEASE.jar

這個命令會輸出不少結果,咱們僅看下其中的一部分:依賴關係按照包分組,若是在classpath上找不到依賴,則顯示"not found".

org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar
   org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.io                                            
      -> java.lang                                          
      -> java.lang.annotation                               
      -> java.lang.ref                                      
      -> java.lang.reflect                                  
      -> java.util                                          
      -> java.util.concurrent                               
      -> org.apache.commons.logging                         not found
      -> org.springframework.asm                            not found
      -> org.springframework.asm.commons                    not found
   org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.lang                                          
      -> java.lang.annotation                               
      -> java.lang.reflect                                  
      -> java.util

相關源碼位置

https://gitee.com/sanri/example/tree/master/testjava8

一點小推廣

創做不易,但願能夠支持下個人開源軟件,及個人小工具,歡迎來 gitee 點星,fork ,提 bug 。

Excel 通用導入導出,支持 Excel 公式
博客地址:https://blog.csdn.net/sanri1993/article/details/100601578
gitee:https://gitee.com/sanri/sanri-excel-poi

使用模板代碼 ,從數據庫生成代碼 ,及一些項目中常常能夠用到的小工具
博客地址:https://blog.csdn.net/sanri1993/article/details/98664034
gitee:https://gitee.com/sanri/sanri-tools-maven

相關文章
相關標籤/搜索