一篇整理JDK8新特性

static?default? lamda表達式?

package com.wanke.microgrid.mgcc;

@FunctionalInterface
public interface NullAnnotation {

  //抽象方法
  public void getName(String a);
  
  boolean equals(Object obj);
  
 //default方法
  default void getAge(){
        System.out.println("age");
    }

   default void getAge1(){
    }
   //靜態方法 
   static  void static1(){
        System.out.println("static1");
    }
    static  void static2(){

   }
}
package com.wanke.microgrid.mgcc;

public class Test{
    public static void main(String[] args) {
        String a = "aaaa";
        //Lambda表達式
        NullAnnotation annotation = (f) -> System.out.println(f);
        annotation.getName(a);
        //defalut方法屬於對象的默認方法
        annotation.getAge();
        //static屬於類的方法
        NullAnnotation.static1();
    }
}

運行結果:

aaaa
age
static1

@FunctionalInterface標記接口爲函數式接口,函數式接口有且只能有一個抽象方法,或許大家會問你不是寫了兩個抽象方法嗎?java.lang.Object根對象有equals方法吧,所以實現該類的時候是不是不必須要實現這個接口(所有的類都是實現java.lang.Object的)。Lambda表達式是基於函數式接口的

常見的函數式接口

package com.wanke.microgrid.mgcc;


import java.util.Comparator;
import java.util.Objects;
import java.util.function.*;

public class Test {
    //Consumer消費型接口,有參無返回
    static void testConsumer(Integer x, Consumer<Integer> consumer) {
        consumer.accept(x);
    }

   //suplier供給型接口,無參有返回值
    static void testSupplier(Supplier<Integer> supplier) {
        System.out.println(supplier.get());
    }

   static Integer getInteger() {
        return 2;
    }

   //函數式接口,有參有返回值
    static void testFunction(Integer num, Function<Integer, Integer> function) {
        System.out.println(function.apply(num));
    }

   //斷言型接口,有參有返回值,返回值是boolean類型
    static void testPredicate(Integer num, Predicate<Integer> predicate) {
        System.out.println(predicate.test(num));
    }

   //介紹部分拓展接口

   //BinaryOperator (R apply(T t, U u) ->兩個輸入,一個輸出,而且類型一樣)
    public static void binaryOperatorCompute(Integer para1, Integer para2, BinaryOperator<Integer> binaryOperator) {
        //使用自定義BinaryOperator
        System.out.println(binaryOperator.apply(para1, para2));
        Comparator<Integer> cpt2 = (x, y) -> Integer.compare(x, y);
        //靜態方法傳入比較器生成BinaryOperator
        BinaryOperator<Integer> min = BinaryOperator.minBy(cpt2);
        System.out.println(min.apply(para1, para2));
    }

   //toIntFunction (int applyAsInt(T t, U u) ->兩個輸入,一個int輸出)
    public static void testToIntFunction(Integer para1, Integer para2, ToIntBiFunction<Integer, Integer> toIntBiFunction) {
        System.out.println(toIntBiFunction.applyAsInt(para1, para2));
    }

   //BiFunction (R apply(T t, U u) ->兩個輸入,一個輸出)
    public static void testBi(Integer para1,Integer para2,BiFunction<Integer, Integer, Integer> biFunction, Function<Integer, Integer> function) {
        BiFunction<Integer, Integer, Integer> newBi = biFunction.andThen(function);
        System.out.println(newBi.apply(para1,para2));


   }
    //如何看出輸入輸出,以BiFunction爲例
    //源碼如下:
//package java.util.function;
//
//import java.util.Objects;
//
//    /**
//     * Represents a function that accepts two arguments and produces a result.
//     * This is the two-arity specialization of {@link Function}.
//     *
//     * <p>This is a <a href="package-summary.html">functional interface</a>
//     * whose functional method is {@link #apply(Object, Object)}.
//     *
//     * @param <T> the type of the first argument to the function
//     * @param <U> the type of the second argument to the function
//     * @param <R> the type of the result of the function
//     *
//     * @see Function
//     * @since 1.8
//     */
//    @FunctionalInterface
//    public interface BiFunction<T, U, R> {
//
//        /**
//         * Applies this function to the given arguments.
//         *
//         * @param t the first function argument
//         * @param u the second function argument
//         * @return the function result
//         */
//        R apply(T t, U u);
//
//        /**
//         * Returns a composed function that first applies this function to
//         * its input, and then applies the {@code after} function to the result.
//         * If evaluation of either function throws an exception, it is relayed to
//         * the caller of the composed function.
//         *
//         * @param <V> the type of output of the {@code after} function, and of the
//         *           composed function
//         * @param after the function to apply after this function is applied
//         * @return a composed function that first applies this function and then
//         * applies the {@code after} function
//         * @throws NullPointerException if after is null
//         */
//        default <V> java.util.function.BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
//            Objects.requireNonNull(after);
//            return (T t, U u) -> after.apply(apply(t, u));
//        }
//    }
//函數式接口類型的唯一抽象方法 R apply(T t, U u);顯然是量輸入一輸出,而且是泛型


  public static void main(String[] args) {
        testConsumer(1, x -> System.out.println(x));
        testSupplier(() -> getInteger());
        testFunction(100, x -> x + 100);
        testPredicate(100, x -> x.equals(100));
        binaryOperatorCompute(1, 2, (x, y) -> x + y);
        testToIntFunction(3, 4, (x, y) -> x + y + 1);
        testBi(5,9,(x,y)->{int z = x+y;return z;},x->x + 3);
    }

}

運行結果:

1
2
200
true
3
1
8
17

總之jdk8提供了一種方便的方式讓我們傳遞函數,就像傳遞參數一樣,大家對照着可以看看js的回調。

方法引用

定義了4個方法的Car這個類作爲例子,區分Java中支持的4種不同的方法引用。

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 );

   final List< Car > cars = Arrays.asList( car ); 

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

   cars.forEach( Car::collide );

第三種方法引用是特定類的任意對象的方法引用,它的語法是Class::method。請注意,這個方法沒有參數。

   cars.forEach( Car::repair );

第四種方法引用是特定對象的方法引用,它的語法是instance::method。請注意,這個方法接受一個Car類型的參數

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

   cars.forEach( police::follow )

方法和函數都有輸入輸出,本質上是類似的,所以我們可以引用方法來代替lamda表達式,這樣或許好理解一點。

Stream總結

Stream的操作符大體上分爲兩種:中間操作符和終止操作符

中間操作符
對於數據流來說,中間操作符在執行制定處理程序後,數據流依然可以傳遞給下一級的操作符。

中間操作符包含8種(排除了parallel,sequential,這兩個操作並不涉及到對數據流的加工操作):

1.map(mapToInt,mapToLong,mapToDouble) 轉換操作符,把比如A->B,這裏默認提供了轉int,long,double的操作符。

2.flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 變成 2,3,4 也就是從原來的一個數據變成了3個數據,這裏默認提供了拍平成int,long,double的操作符。

3.limit 限流操作,比如數據流中有10個 我只要出前3個就可以使用。

4.distint 去重操作,對重複元素去重,底層使用了equals方法。

5.filter 過濾操作,把不想要的數據過濾。

6.peek 挑出操作,如果想對數據進行某些操作,如:讀取、編輯修改等。
skip 跳過操作,跳過某些元素。

7.sorted(unordered) 排序操作,對元素排序,前提是實現Comparable接口,當然也可以自定義比較器。

終止操作符

數據經過中間加工操作,就輪到終止操作符上場了;終止操作符就是用來對數據進行收集或者消費的,數據到了終止操作這裏就不會向下流動了,終止操作符只能使用一次。

1.collect 收集操作,將所有數據收集起來,這個操作非常重要,官方的提供的
Collectors 提供了非常多收集器,可以說Stream 的核心在於Collectors。

2.count 統計操作,統計最終的數據個數。

3.findFirst、findAny 查找操作,查找第一個、查找任何一個 返回的類型爲Optional。

4.noneMatch、allMatch、anyMatch 匹配操作,數據流中是否存在符合條件的元素 返回值爲bool 值。

5.min、max 最值操作,需要自定義比較器,返回數據流中最大最小的值。

6.reduce 規約操作,將整個數據流的值規約爲一個值,count、min、max底層就是使用reduce。

7.forEach、forEachOrdered 遍歷操作,這裏就是對最終的數據進行消費了。

8.toArray 數組操作,將數據流的元素轉換成數組。

parallel會利用多核,但要注意線程安全(利用外部變量時可能會造成線程安全問題,外部變量指的是流操作外面申明的變量)

Optinal用法介紹

  //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);

   //Optional.empty():所有null包裝成的Optional對象:
        Optional<Integer> optional4 = Optional.ofNullable(null);
        Optional<Integer> optional5 = Optional.ofNullable(null);
        System.out.println(optional4 == optional5);// true
        System.out.println(optional5 == Optional.<Integer>empty());// true
        Object o1 = Optional.<Integer>empty();
        Object o2 = Optional.<String>empty();
        System.out.println(o1 == o2);// true


   //isPresent():判斷值是否存在
        Optional<Integer> optional6 = Optional.ofNullable(1);
        Optional<Integer> optional7 = Optional.ofNullable(null);

// isPresent判斷值是否存在
        System.out.println(optional6.isPresent() == true);
        System.out.println(optional7.isPresent() == false);


Optional<Integer> optional8 = Optional.ofNullable(1);
        Optional<Integer> optional9 = Optional.ofNullable(null);

 // 如果不是null,調用Consumer
        optional8.ifPresent(new Consumer<Integer>() {
            @Override
            public void accept(Integer t) {
                System.out.println("value is " + t);
            }
        });

// null,不調用Consumer
        optional9.ifPresent(new Consumer<Integer>() {
            @Override
            public void accept(Integer t) {
                System.out.println("value is " + t);
            }
        });

//orElse(value):如果optional對象保存的值不是null,則返回原來的值,否則返回value
        Optional<Integer> optional10 = Optional.ofNullable(1);
        Optional<Integer> optional11 = Optional.ofNullable(null);

// orElse
        System.out.println(optional10.orElse(1000) == 1);// true
        System.out.println(optional11.orElse(1000) == 1000);// true

 //orElseGet(Supplier supplier):功能與orElse一樣,只不過orElseGet參數是一個對象
        Optional<Integer> optional12 = Optional.ofNullable(1);
        Optional<Integer> optional13 = Optional.ofNullable(null);

 System.out.println(optional12.orElseGet(() -> {
            return 1000;
        }) == 1);//true

System.out.println(optional3.orElseGet(() -> {
            return 1000;
        }) == 1000);//true

//orElseThrow():值不存在則拋出異常,存在則什麼不做,有點類似Guava的Precoditions
        Optional<Integer> optional14 = Optional.ofNullable(1);
        Optional<Integer> optional15 = Optional.ofNullable(null);

optional14.orElseThrow(()->{throw new IllegalStateException();});

try
        {
            // 拋出異常
            optional15.orElseThrow(()->{throw new IllegalStateException();});
        }
        catch(IllegalStateException e )
        {
            e.printStackTrace();
        }

//filter(Predicate):判斷Optional對象中保存的值是否滿足Predicate,並返回新的Optional。
        Optional<Integer> optional16 = Optional.ofNullable(1);
        Optional<Integer> optional17 = Optional.ofNullable(null);

 Optional<Integer> filter1 = optional16.filter((a) -> a == null);
        Optional<Integer> filter2 = optional16.filter((a) -> a == 1);
        Optional<Integer> filter3 = optional17.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

//map(Function):對Optional中保存的值進行函數運算,並返回新的Optional(可以是任何類型)
        Optional<Integer> optional18 = Optional.ofNullable(1);
        Optional<Integer> optional19 = Optional.ofNullable(null);

Optional<String> str1Optional = optional18.map((a) -> "key" + a);
        Optional<String> str2Optional = optional19.map((a) -> "key" + a);

 //flatMap():功能與map()相似,差別請看如下代碼。flatMap方法與map方法類似,區別在於mapping函數的返回值不同。map方法的mapping函數返回值可以是任何類型T,而flatMap方法的mapping函數必須是Optional。
        Optional<Integer> optional1 = Optional.ofNullable(1);

Optional<Optional<String>> str3Optional = optional1.map((a) -> {
            return Optional.<String>of("key" + a);
        });

 Optional<String> str4Optional = optional1.flatMap((a) -> {
            return Optional.<String>of("key" + a);
        });

 System.out.println(str3Optional.get().get());// key1
        System.out.println(str4Optional.get());// key1


//Optional應用示例
        Person person = new Person();
        Car car = new Car();
        Insurance insurance = new Insurance();
        insurance.setName("aa");
        car.setInsurance(insurance);
        person.setCar(car);
        String insuranceName = Optional.ofNullable(person)
                .map((p) -> p.getCar())
                .map(c -> c.getInsurance())
                .map(i -> i.getName()).orElse("unknown");

System.out.println(insuranceName);


}

   static class Person {

private Car car;

public Car getCar() {
           return car;
       }

 public void setCar(Car car) {
           this.car = car;
       }
   }

 static class Car {

private Insurance insurance;

public Insurance getInsurance() {
            return insurance;
        }

public void setInsurance(Insurance insurance) {
            this.insurance = insurance;
        }
    }

 static class Insurance {

private String name;

public String getName() {
            return name;
        }

 public void setName(String name) {
            this.name = name;
        }
    }

新的日期API LocalDate | LocalTime | LocalDateTime

新的日期API都是不可變的,更使用於多線程的使用環境中

@Test
public void test(){
    // 從默認時區的系統時鐘獲取當前的日期時間。不用考慮時區差
    LocalDateTime date = LocalDateTime.now();
    //2018-07-15T14:22:39.759
    System.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);
}
   @Test
   public 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());
    }
   @Test
    public 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());
    }
@Test
    public 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);
    }
   @Test
   public 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);
    }
   @Test
    public 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);
    }
   // ZoneTime  ZoneDate       ZoneDateTime
    @Test
    public 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);
    }

LocalDate

public static void localDateTest() {

  //獲取當前日期,只含年月日 固定格式 yyyy-MM-dd    2018-05-04
        LocalDate today = LocalDate.now();

  // 根據年月日取日期,5月就是5,
        LocalDate oldDate = LocalDate.of(2018, 5, 1);

 // 根據字符串取:默認格式yyyy-MM-dd,02不能寫成2
        LocalDate yesteday = LocalDate.parse("2018-05-03");

// 如果不是閏年 傳入29號也會報錯
        LocalDate.parse("2018-02-29");
    }
 /**
     * 日期轉換常用,第一天或者最後一天...
     */
    public static void localDateTransferTest(){
        //2018-05-04
        LocalDate today = LocalDate.now();
        // 取本月第1天: 2018-05-01
        LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        // 取本月第2天:2018-05-02
        LocalDate secondDayOfThisMonth = today.withDayOfMonth(2);
        // 取本月最後一天,再也不用計算是28,29,30還是31: 2018-05-31
        LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        // 取下一天:2018-06-01
        LocalDate firstDayOf2015 = lastDayOfThisMonth.plusDays(1);
        // 取2018年10月第一個週三 so easy?:  2018-10-03
        LocalDate thirdMondayOf2018 = LocalDate.parse("2018-10-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.WEDNESDAY));
    }

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");
    }

LocalDateTime

//轉化爲時間戳  毫秒值
        long time1 = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
        System.out.println(time1);

 //時間戳轉化爲localdatetime
        DateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");

        System.out.println(df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time1),ZoneId.of("Asia/Shanghai"))));

CompletableFuture異步編程

https://cloud.tencent.com/developer/article/1366581

jdk1.8-ForkJoin框架剖析

https://www.jianshu.com/p/f777abb7b251

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章