JAVA8新特性

炒燜煎糖板栗 發表於 2021-10-19
Java Java 8

介面中預設方法修飾為普通方法

在jdk8之前,interface之中可以定義變數和方法,變數必須是public、static、final的,方法必須是public、abstract的,由於這些修飾符都是預設的。

介面定義方法:public 抽象方法 需要子類實現

介面定義變數:public、static、final

在JDK 1.8開始 支援使用static和default 修飾 可以寫方法體,不需要子類重寫。

方法:

普通方法 可以有方法體

抽象方法 沒有方法體需要子類實現 重寫。

案例

public interface JDK8Interface {
    /*
    * 預設就是public abstract  JDK7之前不能有方法體
    * */
    void add();

    /*
    * jdk8 提供預設實現
    * */
    default void  get() {
        System.out.println("default方法可以寫方法體");
    }

    static void getStaticOrder() {
        System.out.println("靜態方法可以寫方法體");
    }
}

子類實現介面

public class JDK8InterfaceImpl implements  JDK8Interface {
    /*
    * 子類實現介面 沒有強制要求重寫default和static方法
    * */
    @Override
    public void add() {
        System.out.println("add方法");
    }

}

方法呼叫

public class Test01 {
    public static void main(String[] args) {
        JDK8Interface jdk8Interface=new JDK8InterfaceImpl();
        jdk8Interface.add();
        jdk8Interface.get();

        JDK8Interface.getStaticOrder();
    }
}

image-20211018202027296

Lambda表示式

是一個匿名函式,簡化我們呼叫匿名函式的過程

Lambda好處: 簡化我們匿名內部類的呼叫。

Lambda+方法引入 程式碼變得更加精簡。

    public static void main(String[] args) {
        //使用匿名內部類的方式呼叫
//        new OrderService(){
//            @Override
//            public void addOrder() {
//                System.out.println("addorder");
//            }
//        }.addOrder();
        ((OrderService) () -> System.out.println("addorder")).addOrder();

//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                System.out.println(Thread.currentThread().getName()+"執行");
//            }
//        }).start();
        new Thread(() -> System.out.println(Thread.currentThread().getName()+"執行")).start();

    }

Lambda表示式的規範

使用Lambda表示式 依賴於函式介面

  1. 在介面中只能夠允許有一個抽象方法

  2. 在函式介面中定義object類中方法

  3. 使用預設或者靜態方法

  4. @FunctionalInterface 表示該介面為函式介面

Java中使用Lambda表示式的規範,必須是為函式介面

函式介面的定義:在該介面中只能存在一個抽象方法,該介面稱作為函式介面

@FunctionalInterface
public interface MyFunctionalInterface {

    void  get();

    default void add() {

    }
    String toString();
}

常見例如Runnable介面

image-20211018221019469

方法呼叫

    public static void main(String[] args) {
        ((MyFunctionalInterface) () -> System.out.println()).get();
    }

Lambda基礎語法

()--引數列表
-> 分隔
{}  方法體

(函式介面的引數列表 不需要寫型別 需要定義引數名稱)->{方法體}

無參方法呼叫

@FunctionalInterface
public interface MyFunctionalInterface {
    void  get();
}

MyFunctionalInterface myFunctionalInterface= ()->{
     System.out.println("使用lambda表示式");
};

有參帶返回值呼叫

@FunctionalInterface
public interface YouFunctionalInterface {
    String get(int i,int j);
}

    public static void main(String[] args) {
        YouFunctionalInterface youFunctionalInter=(i, j)->{
            return i+"--"+j;
        };
        System.out.println(youFunctionalInter.get(1, 1));
    }

精簡版

public static void main(String[] args) {
        //無參方法原始版本
        MyFunctionalInterface functionalInterface=()->{
            System.out.println("");
        };
        functionalInterface.get();
        //精簡版1
        ((MyFunctionalInterface)()->{
            System.out.println("");
        }).get();
        //精簡版2 在方法體只有一條語句的時候,不需要寫大括號了
        MyFunctionalInterface functionalInterface2=()-> System.out.println("");
        //最終精簡版3
        ((MyFunctionalInterface)()-> System.out.println("")).get();


        //有參方法
        YouFunctionalInterface youFunctionalInterface=(int i,int j)->{
            return "";
        };
        String s = youFunctionalInterface.get(2, 3);

        //精簡版1
        YouFunctionalInterface youFunctionalInterface1=( i, j)->{
            return "";
        };

        //精簡版2
        YouFunctionalInterface youFunctionalInterface2=(i, j)-> i+"--"+j;
        String s1 = youFunctionalInterface1.get(2, 3);

        //最終精簡版3
        String s2 = ((YouFunctionalInterface) (i, j) -> i + "--" + j).get(1, 2);
        System.out.println(s2);
    }

Lambda實戰案例

Foreach

    public static void main(String[] args) {
        ArrayList<String> arrayList=new ArrayList<>();
        arrayList.add("111");
        arrayList.add("222");
        arrayList.add("333");

//        arrayList.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });

        arrayList.forEach(s->{
            System.out.println(s);
        });
    }

Lambda集合排序

public class UserEntity {
    private String name;
    private Integer age;

    public UserEntity(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "UserEntity{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
 public static void main(String[] args) {
        ArrayList<UserEntity> userlists = new ArrayList<>();
        userlists.add(new UserEntity("aa", 22));
        userlists.add(new UserEntity("bb", 18));
        userlists.add(new UserEntity("cc", 36));

        userlists.sort(new Comparator<UserEntity>() {
            @Override
            public int compare(UserEntity o1, UserEntity o2) {
                return o1.getAge()- o2.getAge();
            }
        });

        //精簡遍歷
        userlists.forEach(s-> System.out.println(s));

        //精簡排序
        userlists.sort((o1, o2) -> o1.getAge()- o2.getAge());
    }

Java 8 stream流

Stream 是JDK1.8 中處理集合的關鍵抽象概念,Lambda 和 Stream 是JDK1.8新增的函數語言程式設計最有亮點的特性了,它可以指定你希望對集合進行的操作,可以執行非常複雜的查詢、過濾和對映資料等操作。使用Stream API 對集合資料進行操作,就類似於使用SQL執行的資料庫查詢。Stream 使用一種類似用 SQL 語句從資料庫查詢資料的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。Stream API可以極大提高Java程式設計師的生產力,讓程式設計師寫出高效率、乾淨、簡潔的程式碼

這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等

img

Stream :非常方便精簡的形式遍歷集合實現 過濾、排序等

Stream建立方式

parallelStream為並行流採用多執行緒執行

Stream採用單執行緒執行

parallelStream效率比Stream要高

Stream將list轉換為set

  public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Stream<UserEntity> stream=userEntities.stream();
        Set<UserEntity> collect = stream.collect(Collectors.toSet());
        collect.forEach(s-> System.out.println(s));

    }

set集合底層依賴於map 集合,map集合底層基於equals和hashcode比較防止重複

Stream將list轉換為map

public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        /*
        * list集合只有key  list轉換map的時候需要指定key value,key=username  value=user物件
        * */
        Stream<UserEntity> stream=userEntities.stream();
        Map<String,UserEntity> collect = stream.collect(Collectors.toMap(new Function<UserEntity,String>() {
            @Override
            public String apply(UserEntity o) {
                return o.getName();
            }
        }, new Function<UserEntity, UserEntity>() {
            @Override
            public UserEntity apply(UserEntity usrentity) {
                return usrentity;
            }
        }));

        //精簡版
        collect.forEach(new BiConsumer<String, UserEntity>() {
            @Override
            public void accept(String s, UserEntity userEntity) {
                System.out.println(s+","+userEntity);
            }
        });
        //最終精簡版
        collect.forEach((BiConsumer)(s,userEntity)->System.out.println(s+","+userEntity));
    }

Stream將Reduce 求和

  public static void main(String[] args) {
        Stream<Integer> integerStream=Stream.of(5,6,7,8);
        Optional<Integer> reduce = integerStream.reduce(new BinaryOperator<Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2) {
                return integer + integer2;
            }
        });
        System.out.println(reduce);

        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Optional<UserEntity> sum=userEntities.stream().reduce(new BinaryOperator<UserEntity>() {
            @Override
            public UserEntity apply(UserEntity userEntity, UserEntity userEntity2) {
                UserEntity userEntity1=new UserEntity("sum",userEntity.getAge()+userEntity2.getAge());
                return userEntity1;
            }
        });
        System.out.println(sum);
    }

Stream求最大最小

    public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Stream<UserEntity> stream=userEntities.stream();
        Optional<UserEntity> min = stream.min(new Comparator<UserEntity>() {
            @Override
            public int compare(UserEntity o1, UserEntity o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        System.out.println(min.get());

        //簡化版
        Optional<UserEntity> min1 = stream.min((o1, o2) -> o1.getAge() - o2.getAge());
        System.out.println(min1.get());
    }

Stream Match 匹配

anyMatch表示,判斷的條件裡,任意一個元素成功,返回true

allMatch表示,判斷條件裡的元素,所有的都是,返回true

noneMatch跟allMatch相反,判斷條件裡的元素,所有的都不是,返回true

  public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Stream<UserEntity> stream=userEntities.stream();

        boolean b = stream.anyMatch(new Predicate<UserEntity>() {
            @Override
            public boolean test(UserEntity userEntity) {
                return "aa".equals(userEntity.getName());
            }
        });
        System.out.println(b);

        //簡化版
        boolean b1 = stream.anyMatch((userEntity) -> "aa".equals(userEntity.getName()));
        System.out.println(b1);
    }

Stream for迴圈

    public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Stream<UserEntity> stream=userEntities.stream();
        stream.forEach((userEntity -> System.out.println(userEntity)));
    }

Stream filter過濾器

    public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Stream<UserEntity> stream=userEntities.stream();
        stream.filter(new Predicate<UserEntity>() {
            @Override
            public boolean test(UserEntity userEntity) {
                return "aa".equals(userEntity.getName()) && userEntity.getAge() >= 18;
            }
        }).forEach((userEntity -> System.out.println(userEntity)));

        //精簡版
        stream.filter((userEntity)->"aa".equals(userEntity.getName()) && userEntity.getAge() >= 18)
                .forEach((userEntity -> System.out.println(userEntity) ));
    }

Stream limit和skip

Limit 從頭開始獲取

Skip 就是跳過

    public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("aa", 20));
        userEntities.add(new UserEntity("bb", 28));
        userEntities.add(new UserEntity("cc", 35));
        userEntities.add(new UserEntity("dd", 16));

        Stream<UserEntity> stream = userEntities.stream();
        stream.skip(2).limit(2).forEach((userEntity -> System.out.println(userEntity)));
    }

stream 綜合案例

 public static void main(String[] args) {
        ArrayList<UserEntity> userEntities = new ArrayList<>();
        userEntities.add(new UserEntity("mayikt", 20));
        userEntities.add(new UserEntity("meite", 28));
        userEntities.add(new UserEntity("zhangsan", 35));
        userEntities.add(new UserEntity("xiaowei", 16));
        userEntities.add(new UserEntity("mayikt_list", 109));
        userEntities.add(new UserEntity("mayikt_zhangsan", 110));
        userEntities.add(new UserEntity("lisi", 109));
        userEntities.add(new UserEntity("mayikt", 100));
        userEntities.add(new UserEntity("mayikt", 60));


        Stream<UserEntity> stream=userEntities.stream();
        stream.sorted((o1,o2)->o1.getAge()-o2.getAge())
                .filter((userEntity -> "mayikt".equals(userEntity.getName())))
                .limit(3)
                .forEach((userEntity)-> System.out.println(userEntity));
    }

並行流與序列流區別

序列流:單執行緒的方式操作; 資料量比較少的時候。

並行流:多執行緒方式操作;資料量比較大的時候

原理:Fork join 將一個大的任務拆分n多個小的子任務並行執行,最後在統計結果,有可能會非常消耗cpu的資源,確實可以提高效率。

注意:資料量比較少的情況下,不要使用並行流

方法引用

什麼是方法引入

方法引入:需要結合lambda表示式能夠讓程式碼變得更加精簡

  1. 靜態方法引入: 類名::(靜態)方法名稱

  2. 物件方法引入 類名:: 例項方法名稱

  3. 例項方法引入 new物件 物件例項::方法引入

  4. 建構函式引入 類名::new

需要遵循一個規範:

方法引入 方法引數列表、返回型別與函式介面引數列表與返回型別必須要保持一致。

靜態方法引入

/*
* 靜態方法引入
* */
public class Test01 {
    public static void main(String[] args) {
        MyFunctionalInterface myFunctionalInterface = () -> {
            /*引入getStaticMethod方法*/
            Test01.getStaticMethod();
        };
        myFunctionalInterface.get();

        // 使用方法引入呼叫方法 必須滿足:方法引入的方法必須和函式介面中的方法引數列表/返回值一定保持一致。
        MyFunctionalInterface messageInterface = Test01::getStaticMethod;
        messageInterface.get();
    }
    public static void getStaticMethod() {
        System.out.println("我是 getMethod");
    }
}

例項物件方法引入

public class Test02 {
    public static void main(String[] args) {
        Test02 test02=new Test02();
        MyFunctionalInterface myFunctionalInterface = () -> {
            /*引入getStaticMethod方法*/
            test02.getStaticMethod();
        };
        myFunctionalInterface.get();

        // 精簡版
        MyFunctionalInterface messageInterface = test02::getStaticMethod;
        messageInterface.get();


    }
    public  void getStaticMethod() {
        System.out.println("我是 getMethod2");
    }
}

建構函式引入

    public static void main(String[] args) {
        UserInterface userInterface=new UserInterface() {
            @Override
            public UserEntity getUser() {
                return new UserEntity();
            }
        };

        //精簡版
        UserInterface userInterface3=UserEntity::new;
        userInterface2.getUser();

    }

物件方法引入

public class Test04 {
    public static void main(String[] args) {
        Myservice myservice=new Myservice() {
            @Override
            public String get(Test04 test04) {
                return test04.objGet();
            }
        };

        Myservice myservice1=(Test04-> Test04.objGet());

        //精簡版  傳入Test04 返回string值
        Myservice myservice2=Test04::objGet;


        Function<String,Integer> function=new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();
            }
        };
        //精簡版
        Function<String,Integer> function2=String::length;
        System.out.println(function2.apply("dfdf"));

    }
@FunctionalInterface
public interface Myservice {
    String get(Test04 userEntity);
}

JDK8Optional

Optional 類是一個可以為null的容器物件。如果值存在則isPresent()方法會返回true,呼叫get()方法會返回該物件。

Optional 是個容器:它可以儲存型別T的值,或者僅僅儲存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。

Optional 類的引入很好的解決空指標異常。

判斷引數是否為空

ofNullable(可以傳遞一個空物件)

Of(不可以傳遞空物件)

    public static void main(String[] args) {
        String username=null;
        Integer a1 = 1;
        Optional<Integer> a = Optional.ofNullable(a1);
        System.out.println(a.isPresent());//true

        Optional<String> username1 = Optional.ofNullable(username);
        System.out.println(username1.isPresent());//false
    }

isPresent表示結果返回是否為空, true 不為空,返回 false 為空

引數為空可以設定預設值

    public static void main(String[] args) {
        Integer a1 = null;
        Integer a = Optional.ofNullable(a1).orElse(10);
        System.out.println(a);//10
    }

引數實現過濾

public static void main(String[] args) {
    Integer a1 = 16;
    Optional<Integer> a = Optional.ofNullable(a1);
    //判斷是否等於16
    boolean present = a.filter(new Predicate<Integer>() {
        @Override
        public boolean test(Integer integer) {
            return integer.equals(16);
        }
    }).isPresent();
    System.out.println(present);//true

    boolean isPresent = a.filter(a2 -> a2==17).isPresent();
    System.out.println(isPresent);//false
}

與Lambda表示式結合使用,優化程式碼

優化方案1

    public static void main(String[] args) {
        // 優化前
        String name = "meite";
        if (name != null) {
            System.out.println(name);
        }
        //優化後
        Optional<String> name2 = Optional.ofNullable(name);
        // 當value 不為空時,則不會呼叫
        name2.ifPresent(s -> System.out.println(s));
        name2.ifPresent(System.out::print);
    }

優化方案2

public class Test05 {
    private static UserEntity userEntity = null;

    public static void main(String[] args) {
        UserEntity userEntity = Test05.getOrder();
        System.out.println(userEntity);
    }
    public static UserEntity getOrder() {
        // 優化前
        if (userEntity == null) {
            return createOrder();
        }
        return userEntity;
         //優化1
        return Optional.ofNullable(Test05.userEntity).orElseGet(new Supplier<UserEntity>() {
            @Override
            public UserEntity get() {
                return createOrder();
            }
        });

        //優化2
        return Optional.ofNullable(Test05.userEntity).orElseGet(()-> {
           Test05.userEntity =createOrder();
           return Test05.userEntity;
        });

        //精簡版
        return Optional.ofNullable(Test05.userEntity).orElseGet(() -> createOrder());
    }

    private static UserEntity createOrder() {
        return new UserEntity("ylc", 12);
    }
}

優化方案3

public class Test06 {
    public static void main(String[] args) {

        String orderName = Test06.getOrderName();
        System.out.println(orderName);
    }
    public static String getOrderName() {
        // 優化前寫法:
        UserEntity userEntity = new UserEntity("123456", 19);
        if (userEntity != null) {
            String userEntityName = userEntity.getName();
            if (userEntityName != null) {
                return userEntityName.toLowerCase();
            }
        }
        //優化後
        Optional<String> s1 = Optional.ofNullable(userEntity)
                .map((s) -> s.getName())
                .map((s) -> s.toLowerCase());

        return s1.get();
    }
}