Jdk1.8新特性之Lambda表達式


針對jdk1.8新特性,特來做個小結

一.Lambda表達式的使用

 lambda表達式也叫函數式編程 :Lambda需要函數式接口支持,並且接口中的抽象方法只能有一個
函數式接口:接口中只有一個抽象方法的接口,稱之為函數式接口。可以使用@FunctionalInterface修飾,該注解可以檢查是否是函數式接口。

自己的理解就是可以 lambda表達式向數據一樣傳遞

直接上代碼體會

 //原來匿名內部類
    @Test
    public void test1() {
        //比較器
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };

        TreeSet<Integer> ts = new TreeSet<>(com);
    }

    //現在的 Lambda 表達式
    @Test
    public void test2() {
        //比較器
        Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

        TreeSet<Integer> ts = new TreeSet<>(com);
    }

 

 

JDK1.8之前處理需求

1.new集合 2.遍歷 3.if判斷

 //需求:獲取工資大於 5000 的員工的信息
    public List<Employee> filterEmployeeBySalary(List<Employee> employees) {
        List<Employee> list = new ArrayList<>();

        for (Employee employee : employees) {
            if (employee.getSalary() >= 5000) {
                list.add(employee);
            }
        }

        return list;
    }

   

 

可以發現弊端:當需求有變更 新增過濾條件 又需要遍歷一遍 if判斷  實際需要的代碼只有一句if (employee.getAge() > 18)  卻要寫大量冗余代碼 很惡心

 

 //需求:獲取年齡大於 18  的員工的信息
    public List<Employee> filterEmployeeByAge(List<Employee> employees) {
        List<Employee> list = new ArrayList<>();

        for (Employee employee : employees) {
            if (employee.getAge() > 18) {
                list.add(employee);
            }
        }

        return list;
    }

 

 優化思路:策略模式

1.定義接口  作為過濾條件

public interface MyPredicate<T> {
    
    public boolean test(T t);

}

 2.接口實現  設置過濾條件

public class FilterEmployeeBySalary implements MyPredicate<Employee>{

    @Override
    public boolean test(Employee t) {
        return t.getSalary() >= 5000;
    }

}
public class FilterEmployeeByAge implements MyPredicate<Employee> {

    @Override
    public boolean test(Employee t) {
        return t.getAge() > 18;
    }

}

3.定義filter方法 傳入需要過濾集合,和過濾條件接口

  //優化方式一:策略設計模式
    public List<Employee> filterEmployees(List<Employee> employees, MyPredicate<Employee> mp) {
        List<Employee> list = new ArrayList<>();

        for (Employee employee : employees) {
            if (mp.test(employee)) {
                list.add(employee);
            }
        }
        return list;
    }

4.測試

@Test
    public void test4() {
        List<Employee> list = filterEmployees(employees, new FilterEmployeeBySalary());

        for (Employee employee : list) {
            System.out.println(employee);
        }

        System.out.println("---------------------------------");

        List<Employee> list2 = filterEmployees(employees, new FilterEmployeeByAge());

        for (Employee employee : list2) {
            System.out.println(employee);
        }
    }

 

使用匿名內部類簡化代碼

 //優化方式二:策略設計模式 + 匿名內部類
    @Test
    public void test5() {
        List<Employee> list = filterEmployees(employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee t) {
                return t.getSalary() >= 5000;
            }
        });

        for (Employee employee : list) {
            System.out.println(employee);
        }
    }

 

使用lambda表達式 更加簡潔

 //優化方式三:策略設計模式 + Lambda 表達式
    @Test
    public void test6() {
        List<Employee> list = filterEmployees(employees, (e) -> e.getSalary() >= 5000);
        list.forEach(System.out::println);
    }

 

弊端:每增加一個過濾條件都需要寫一份實現類

能不能不寫接口和實現類就實現對集合的過濾?答案是肯定的

在JDK1.8中 引入流操作,使用Stream+Lambda表達式  極大簡化代碼

//優化方式四:Stream API
    @Test
    public void test7() {
        employees.stream()
                .filter((e) -> e.getSalary() >= 5000)
                .forEach(System.out::println);

        System.out.println("---------------------------------------");

        employees.stream()
                .map(Employee::getName)
                .forEach(System.out::println);
    }

 lambda表達式的基本使用規則:

/**
     * lambda表達式
     * 左側:Lambda表達式的參數列表
     * 右側:Lambda表達式所執行的功能,即lambda體
     * 接口中只能有一個實現類
     */
    @Test
    public void test8() {
        //Consumer接口中只有一個抽象方法,和一個接口默認方法
        Consumer<String> con = (x) -> System.out.println("Yan:" + x);
        con.accept("我是YanYan啊");
    }

    @Test
    public void test9() {
        //lambda體中有多條語句,必須使用大括號
        Comparator<Integer> com = (x, y) -> {
            System.out.println("Comparator接口");
            return x.compareTo(y);
        };
        com.compare(1, 2);

    }
//原來匿名內部類
    @Test
    public void test1() {
        //比較器
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };

        TreeSet<Integer> ts = new TreeSet<>(com);
    }

    //現在的 Lambda 表達式
    @Test
    public void test2() {
        //比較器
        Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

        TreeSet<Integer> ts = new TreeSet<>(com);
    }
//Demo1
@FunctionalInterface
interface MyFun { Integer getValue(Integer num); } public Integer operation(Integer num, MyFun mf) { return mf.getValue(num); } @Test public void test10() { System.out.println(operation(10, (x) -> x * x)); System.out.println(operation(1, x -> x + x)); }

 

//Demo2
@FunctionalInterface
interface HandleStr { String handle(String str); } public String strHandle(String str, HandleStr hs) { return hs.handle(str); } @Test public void test2() { String str = "zhangyan"; System.out.println( strHandle(str, x -> { //轉換成大寫 return x.toUpperCase().substring(1, 3); })); }
//Demo3
@FunctionalInterface
interface MyFun3<T, R> { R getValue(T t1, T t2); } public void op(Long l1, Long l2, MyFun3<Long, Long> mf) { System.out.println(mf.getValue(l1, l2)); } @Test public void test3() { op(100l,200l,(x,y)-> x+y); op(10l,15l,(x,y)->{ return x*y; }); }

 

 

 

 

二.JAVA內置四大核心函數式接口

之前我們在使用Lamda表達式中每次都需要自己寫一個接口,然后再去自定義接口的實現類

然而,JKD1.8已經為我們定義了四大函數式接口,配合Lambda表達式使用起來非常方便

/**
 * java內置四大核心函數式接口
 * <p>
 * 1.Consumer<T>消費型接口 無返回值  void accept(T t)
 * 2.Supplier<T>供給型接口 T get();
 * 3.Function<T>函數型接口 R apply(T t)
 * 4.Predicate<T>斷言型接口 用於做判斷操作 boolean test(T t)
 */
public class TestLambda3 {

    //Consumer<T>
    @Test
    public void test1() {
        happy(10.15, (x) -> System.out.println(x));

    }

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


    //Supplier<T> 產生指定個數的隨機數,存入集合
    @Test
    public void test2() {
        this.getNumber(10, () -> (int) Math.random() * 100);
    }

    public List<Integer> getNumber(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }


    //Predicate<T>

    @Test
    public void test3() {
        List<String> strList = Arrays.asList("Mike", "Lee", "Yan");
        //使用時設置條件
        List<String> list = this.filterStr(strList, (x) -> x.length() > 3);
        list.forEach(System.out::print);
    }

    //將滿足條件的字符串 存入集合中
    public List<String> filterStr(List<String> str, Predicate<String> pre) {
        List<String> list = new ArrayList<>();

        for (String s : str) {
            if (pre.test(s)) {
                list.add(s);
            }
        }
        return list;
    }

 

 

 

 

三.方法引用和構造器引用

本質上是lambda表達式的另一種表現形式

* 三種語法格式
* 1.對象 :: 實例方法名
*
* 2.:: 靜態方法名
*
* 3.:: 實例方法名
*/
public class TestMethodRef {

    @Test
    public void test1() {

        Consumer<String> consumer = (x)-> System.out.println(x);

        PrintStream ps = System.out;
        Consumer<String> son =  ps::println;

    }
 @Test
    public void test2() {
        Employee emp = new Employee("Yan", 24, '男', 14000);
        Supplier<String> sup = emp::getName;
       /* Supplier<String> sup2 = new Supplier<String>() {
            @Override
            public String get() {
               return emp.getName();
            }
        };*/

//     與上面語句功能相同    Supplier sup2 = ()->emp.getName();
        String s = sup.get();
        System.out.println(s);
    }


    //類 :: 靜態方法
    @Test
    public void test3() {
        Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);

        Comparator<Integer> com2 = Integer::compare;
    }


    //類 :: 實例方法名

    @Test
    public void test4() {
        BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);

        //限制條件:只有當(x, y) -> x.equals(y) 第一個參數x作為參數的調用者,第二個參數y為方法參數時,才可以使用這種方式
        //ClassName::method
        BiPredicate<String, String> bp2 = String::equals;
    }


    //構造器引用 ClassName::new
    @Test
    public void test5() {
        Supplier<Employee> sup1 = () -> new Employee();
        Employee employee = sup1.get();//接口sup1 調用方法 get()  get方法被() -> new Employee() 重寫

        //調用無參構造器  因為 需要和Supplier get方法中的入參和返回值類型保持一致
        Supplier<Employee> sup2 = Employee::new;


        //如需使用其他構造器則
        BiFunction<String, Integer, Employee> bg1 = (x, y) -> new Employee(x, y);
        System.out.println(bg1.apply("Yan", 23));

        //調用有參構造器,取決於BiFunction中的apply方法的入參
        BiFunction<String, Integer, Employee> bg2 = Employee::new;


    }


    //數組引用 type[] :: new
    @Test
    public void test6() {
        Function<Integer, String[]> fun1 = (x) -> new String[x];
        String[] apply = fun1.apply(10);
        System.out.println(apply);

        Function<Integer, String[]> fun2 = String[]::new;

    }

 

 
        
 
        

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM