開發中裝x必備(編程新風格、新姿勢、新走向)—— Java 8的新特性

一、lambda表達式

/**
 * 1、例子:(int 01,int 02) -> return 01 - 01
 * 2、格式:
 *      ->:lambda表達式操作符
 *      左邊:形參列表(就是接口中的抽象方法的形參列表)
 *      右邊:方法體(重寫抽象方法的方法體)
 * 3、表達式本質:作爲函數式接口(接口中只有一個抽象方法,@FunctionInterface標記)的實例(對象)
 * */

在java中的主角的就是對象,幾乎所有東西都是對象,包括方法(通過反射可以拿到Method對象)。而lambda表達式也不例外,表達式基於接口的抽象方法的,這個是前提。我們來看lambda表達式六種格式。

1、無參數無返回值

public interface InterfaceDemo1 {
    void print();
}
    /**
     * 語法格式1:無參數,無返回值
     */
    public static void test1(){
        //原來的寫法
        InterfaceDemo1 interfaceDemo1 = new InterfaceDemo1() {
            @Override
            public void print() {
                System.out.println("hello 我是原來的寫法");
            }
        };
        interfaceDemo1.print();

        //Lambda表達式寫法
        InterfaceDemo1 demo1 = () -> System.out.println("hello");
        demo1.print();
    }

2、需要參數,無返回值

public interface InterfaceDemo2 {
    void print(String str);
}
    /**
     * 語法格式2:需要參數,無返回值
     */
    public static void test2(){
        //原來的寫法
        InterfaceDemo2 interfaceDemo2 = new InterfaceDemo2() {
            @Override
            public void print(String str) {
                System.out.println("hello 我是原來的寫法");
            }
        };
        interfaceDemo2.print("hello");

        //Lambda表達式寫法
        InterfaceDemo2 demo2 = (String str) -> System.out.println(str);
        demo2.print("hello");
    }

3、數據類型可以省略:由編譯器推斷得出

 /**
     * 語法格式3:數據類型可以省略:由編譯器推斷得出
     */
    public static void test3(){
        InterfaceDemo2 demo2 = (str) -> System.out.println(str);
        demo2.print("hello");
    }

4、只需要一個參數的時候,括號可以省略

    /**
     * 語法格式4:只需要一個參數的時候,括號可以省略
     */
    public static void test4(){
        InterfaceDemo2 demo2 = str -> System.out.println(str);
        demo2.print("hello");
    }

5、需要兩個及以上參數的時候,多條語句執行,並且有返回值

public interface InterfaceDemo3 {
    int print(int a,int b);
}
 /**
     * 語法格式5:需要兩個及以上參數的時候,多條語句執行,並且有返回值
     */
    public static void test5(){
        InterfaceDemo3 interfaceDemo3 = new InterfaceDemo3() {
            @Override
            public int print(int a, int b) {
                System.out.println("hello 我是原來的寫法");
                return a + b;
            }
        };
        System.out.println(interfaceDemo3.print(1,2));

        InterfaceDemo3 demo3 = (a,b) -> {
            System.out.println("hello");
            return a + b;
        };
        System.out.println(demo3.print(1,2));
    }

6、當lambda體只有y一條語句的時候,return與大括號若有,都可以省略

    /**
     * 語法格式6:當lambda體只有y一條語句的時候,return與大括號若有,都可以省略
     */
    public static void test6(){
        InterfaceDemo3 demo3 = (a,b) -> a + b;
        System.out.println(demo3.print(1,2));
    }

大家可以把上面的例子運行一遍,應該就有感覺了。創建的表達式實際上也是一個函數接口的實例。

二、函數式接口

接口中只有一個抽象方法,@FunctionInterface標記。

    public static void test1(){
        //原來寫法
        happyTime(500.0, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("價格 => " + aDouble);
            }
        });

        //lambda
        happyTime(500.0,(money) -> {System.out.println("價格 => " + money);});
    }

    /**
     * Consumer
     */
    public static void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }

這個表達式實例可以當作參數來傳遞,然後調用實際的方法。

    /**
     * Predicate
     */
    public static void test2(){
        List<String> strings = new ArrayList<>();
        strings.add("aaaaa");
        strings.add("bbb");
        strings.add("cccc");
        filterString(strings,(String str) -> {return str.length() > 3;});
    }
    /**
     * Predicate
     */
    public static void filterString(List<String> list, Predicate<String> predicate){
        List<String> strings = new ArrayList<>();
        for(String str:list){
            if(predicate.test(str)){
                strings.add(str);
            }
        }
        System.out.println(strings);
    }

實際上這四個方法,我們只需要按照參數和返回值傳入相應的東西就可以了!!!

三、方法引用與構造器引用

1、方法引用

/**
 * 方法引用的使用
 * 1、使用情景:當要傳遞給lambda體的操作,已經有實現的方法了,可以使用方法引用。
 * 2、方法引用:本質上就是lambda表達式。也是函數接口的實例
 * 3、格式:類(對象)::方法名
 * 4、具體分爲如下幾種情況:
 *      對象::實例方法
 *      類::靜態方法
 *      類::實例方法
 * 5、要求:接口中的抽象方法的形參列表和返回值類型與方法引用的形參列表和返回值相同。
 **/

方法引用,引用的是已經存在的方法,幫我們來執行。

public class User {

    private String name;
    private int age;
    private char sex;

    //constructor、getter、setter...
}
    /**
     * 情景1:對象::實例方法
     * Consumer     void accept(T t)
     * PrintStream  void println(T t)
     */
    public static void test1(){
        //lambda
        Consumer<String> con = str -> System.out.println(str);
        con.accept("hhhhhh");

        //方法引用
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("hhhhh");
    }

    /**
     * Supplier     T get()
     * User     String getName()
     */
    public static void test2(){
        User user = new User("aaa",12,'m');
        Supplier<String> sp = user::getName;
        System.out.println(sp.get());
    }
   /**
     * 情景2:類::靜態方法
     * Comparator   int compare(T t1,T t2)
     * Integer      int compare(int t1,int t2)
     */
    public static void test3(){
        Comparator<Integer> comparator1 = (t1,t2) -> Integer.compare(t1,t2);
        System.out.println(comparator1.compare(1,2));

        Comparator<Integer> comparator2 = Integer::compare;
        System.out.println(comparator2.compare(1,2));
    }


    /**
     * Function     R apply(T t)
     * Math         long round(Double d)
     */
    public static void test4(){
        Function<Double,Long> function1 = (d) -> Math.round(d);
        System.out.println(function1.apply(2.54));

        Function<Double,Long> function2 = Math::round;
        System.out.println(function2.apply(2.1));
    }
    /**
     * 情景3:類::實例方法
     * Comparator       int compare(T t1,T t2)
     * String           int t1.compareTo(t2)
     */
    public static void test5(){
        Comparator<String> comparator1 = (s1,s2) -> s1.compareTo(s2);
        System.out.println(comparator1.compare("hhhh","bbbbb"));

        Comparator<String> comparator2 = String::compareTo;
        System.out.println(comparator2.compare("hhhh","bbbbb"));
    }

    /**
     * BiPredicate        boolean test(T t1,T t2)
     * String           boolean t1.equals(t2)
     */
    public static void test6(){
        BiPredicate<String,String> predicate = (t1, t2) ->  t1.equals(t2);
        System.out.println(predicate.test("aaa","aaa"));

        BiPredicate<String,String> predicate2 = String::equals;
        System.out.println(predicate2.test("aaa","aaa"));

    }

    /**
     * Function     R apply(T t)
     * User       String getName()
     */
    public static void test7(){
        Function<User,String> function1 = (t1) -> t1.getName();
        System.out.println(function1.apply(new User("zhangsan",12,'c')));

        Function<User,String> function2 = User::getName;
        System.out.println(function2.apply(new User("lisi",12,'c')));
    }

要重點注意第三種場景,這種場景之所以成立,是引入傳入的參數(或者第一個參數)實際上是一個對象,然後用對象調用一個方法。

2、構造器引用

/**
 * 一、構造器引用
 *      與方法引用類似,函數式接口的抽象方法的形參列表和構造器的形參列表一致
 *      抽象方法的返回值類型即爲構造器所屬的類的類型
 *
 * 二、數組引用
 *      可以把數組看作是一個特殊的類,則寫法與構造器引用一致
 *
 **/
public class ConstructDemo {

    /**
     * 構造器引用
     * Supplier     T get()
     * User 空參構造器
     */
    public static void test1(){
        Supplier<User> supplier = () -> new User("張三",12,'a');
        System.out.println(supplier.get());

        Supplier<User> supplier1 = User::new;
        System.out.println(supplier1.get());
    }

    /**
     * Function     R apply(T t)
     */
    public static void test2(){
        Function<String,User> function1 = (name) -> new User(name);
        System.out.println(function1.apply("zhangsan "));

        Function<String,User> function2 = User::new;
        System.out.println(function2.apply("lisi "));
    }

    /**
     * BiFunction       apply(T t,U u)
     */
    public static void test3(){
        BiFunction<String,Integer,User> function1 = (name,age) -> new User(name,age);
        System.out.println(function1.apply("zhangsan",12));

        BiFunction<String,Integer,User> function2 = User::new;
        System.out.println(function2.apply("lisi",12));
    }

    /**
     * 情景2:數組引用
     */
    public static void test4(){
        Function<Integer,String[]> function1 = (len) -> new String[len];
        String[] arr1 = function1.apply(10);

        Function<Integer,String[]> function2 = String[]::new;
        String[] arr2 = function2.apply(10);
    }

    public static void main(String[] args) {
        test3();
    }
}

用了new關鍵字!!

四、stream的API

/**
 * 1、stream:關注對數據的運算,與cpu打交道
 *    集合:關注的是數據存儲,與內存打交道
 *
 * 2、stream:
 *      自己不會存儲數據
 *      不會改變源對象,相反會返回一個持有結果的新Stream
 *      操作時延遲的,這意味着他們會等到需要看結果的時候才執行。
 * 3、執行流程:
 *      Stream實例化
 *      一些列中間操作(過濾、映射。。。。)
 *      中止操作(不能再被使用)
 **/
public class UserData {

    public static List<User> getListUser(){
        List<User> list = new ArrayList<>();
        list.add(new User("小明",22,'m'));
        list.add(new User("小剛",32,'m'));
        list.add(new User("小張",24,'f'));
        list.add(new User("小張",24,'f'));
        list.add(new User("小子",200,'m'));
        return list;
    }
}

1、創建Stream

/**
     * 創建一個Stream方式一:集合
     */
    public static void test1(){
        //順序流
        List<User> listUser = UserData.getListUser();
        Stream<User> stream = listUser.stream();

        //並行流
        Stream<User> userStream = listUser.parallelStream();

    }

    /**
     * 創建一個Stream方式二:數組
     */
    public static void test2(){
        int[] arr = new int[]{1,2,3,4,5};
        IntStream stream = Arrays.stream(arr);

    }

    /**
     * 創建一個Stream方式三:Stream的of
     */
    public static void test3(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
    }

2、篩選與分片

package stream;

import method_reference.User;
import method_reference.UserData;

import java.util.List;
import java.util.stream.Stream;

/**
 * 中間操作:篩選與切片
 **/
public class StreamA {

    private static List<User> listUser = UserData.getListUser();
    private static Stream<User> stream = listUser.stream();

    /**
     * 篩選:filter方法api
     */
    public static void test1(){
        stream.filter(u -> u.getAge() > 30).forEach(System.out::println);
    }

    /**
     * 截斷流limit方法api
     */
    public static void test2(){
        stream.limit(3).forEach(System.out::println);
    }

    /**
     * 跳過n數據skip(n)方法api
     */
    public static void test3(){
        stream.skip(2).forEach(System.out::println);
    }

    /**
     * 去重distinct方法,通過流所生成的元素的hashCode()和equals()去重複元素
     */
    public static void test4(){
        stream.distinct().forEach(System.out::println);
    }


    public static void main(String[] args) {
        test4();
    }
}

3、映射

package stream;

import method_reference.User;
import method_reference.UserData;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * 映射
 *
 **/
public class StreamB {

    private static List<User> listUser = UserData.getListUser();
    private static Stream<User> stream = listUser.stream();

    /**
     * map:接收一個函數作爲參數,將元素轉換成其他形式或提取信息,該函數會應用到每一個元素上面,將其映射成一個新的元素
     */
    public static void test1(){
        stream.map(user -> {
            user.setName(user.getName() + "hh");
            return user;
        }).forEach(System.out::println);
    }

    /**
     * flatMap:接收一個函數作爲參數,將流中每一個值轉換成另一個流,然後把所有流連接起來
     */
    public static void test2(){
        List<String> strings = Arrays.asList("aa","bb","cc");
        //正常寫法
        Stream<Stream<Character>> streamStream = strings.stream().map(StreamB::fromStringToStream);
        streamStream.forEach(stream -> {
            stream.forEach(System.out::print);
        });
        System.out.println();
        //flatmap
        strings.stream().flatMap(StreamB::fromStringToStream).forEach(System.out::print);
    }

    public static Stream<Character> fromStringToStream(String str){
        List<Character> list = new ArrayList<>();
        for(char ch:str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }

    public static void main(String[] args) {
        test2();
    }

}

4、排序

package stream;

import java.util.Arrays;
import java.util.List;

/**
 * 排序
 **/
public class StreamC {

    /**
     * 自然排序
     */
    public static void test1(){
        List<Integer> list = Arrays.asList(12,7,9,10,23,57,3);
        list.stream().sorted().forEach(System.out::println);
    }

    /**
     * 比較器排序
     */
    public static void test2(){
        List<Integer> list = Arrays.asList(12,7,9,10,23,57,3);
        list.stream().sorted((a,b) -> b - a).forEach(System.out::println);
    }

    public static void main(String[] args) {
        test2();
    }
}

五、中止操作

package stream;

import method_reference.User;
import method_reference.UserData;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 中止操作
 **/
public class EndDemo {

    private static List<User> listUser = UserData.getListUser();

    /**
     * 匹配與查找
     */
    public static void test1(){
        //allMatch:檢查是否匹配所有元素都大於30
        boolean b = listUser.stream().allMatch(e -> e.getAge() > 30);

        //anyMatch:檢查至少匹配一個元素大於30
        boolean b1 = listUser.stream().anyMatch(e -> e.getAge() > 30);

        //noneMatch:檢查是否沒有匹配元素
        boolean b2 = listUser.stream().noneMatch(e -> e.getName().startsWith("張"));

        //findFirst:查找第一個元素
        Optional<User> first = listUser.stream().findFirst();

        //findAny:返回當前流中的任意元素
        Optional<User> any = listUser.stream().findAny();

        //count:數量
        long count = listUser.stream().filter(e -> e.getAge() > 30).count();

        //找最大:max
        Optional<Integer> max = listUser.stream().map(e -> e.getAge()).max(Integer::compare);

        //找最小:min
        Optional<User> min = listUser.stream().min((a, c) -> a.getAge() - c.getAge());

        //forEash:內部迭代
        listUser.stream().forEach(System.out::println);
        //forEash:外部迭代
        listUser.forEach(System.out::println);
    }

    /**
     * 歸約
     */
    public static void test2(){
        //reduce(T identity,BinaryOperator):可以將流中的值反覆結合起來,得到一個值,返回。
        //identity:初始值
        Integer reduce = listUser.stream().map(e -> e.getAge()).reduce(0, Integer::sum);
        System.out.println(reduce);

        //reduce(BinaryOperator)

    }
     /**
     * 收集:collect
     */
    public static void test3(){
        //將流轉換成其他形式,接收一個Collector接口的實現,用於給Stream中元素做彙總方法
        List<User> userList = listUser.stream().filter(e -> e.getAge() > 30).collect(Collectors.toList());
        Set<User> collect = listUser.stream().filter(e -> e.getAge() > 30).collect(Collectors.toSet());

    }

    public static void main(String[] args) {
        test3();
    }

}

 六、Optional

如果我們傳入null值,那麼就會創建一個非空對象

package optional;

import java.util.Optional;

/**
 * 爲了在程序中避免空指針異常而創建的!!!
 * Optional.of(T t):創建一個Optional實例,t必須非空
 * Optional.empty:創建一個空的Optional實例
 * Optional.ofNullable:t可以爲空
 *
 **/
public class OptionalTest {

    /**
     * Optional.of
     */
    public static void test1(){
        Girl girl = new Girl();
        Optional<Girl> optionalGirl = Optional.of(girl);
    }

    /**
     * Optional.ofNullable
     */
    public static void test2(){
        Optional<Girl> optionalGirl = Optional.ofNullable(null);
    }

    /**
     * 平時寫:空指針
     */
    public static void test3(){
        Boy boy = new Boy();
        System.out.println(boy.getGirl().getName());
    }

    public static void test4(){
        Boy boy = new Boy();

        //保證boy不是null
        Optional<Boy> optionalBoy = Optional.ofNullable(boy);
        //如果boy是空,那麼boy就變成我們new的對象
        optionalBoy.orElse(new Boy(new Girl("hhhh")));

        Girl girl = boy.getGirl();
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        optionalGirl.orElse(new Girl("aaaaa"));

        System.out.println(girl.getName());
    }



    public static class Boy{
        private Girl girl;

        public Boy(){}

        public Boy(Girl girl){
            this.girl = girl;
        }

        public Girl getGirl() {
            return girl;
        }

        public void setGirl(Girl girl) {
            this.girl = girl;
        }
    }

    public static class Girl{
        private String name;

        public Girl(){}

        public Girl(String name){
            this.name = name;
        }

        public String getName() {
            return name;
        }

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

}

 

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