java1.8lambda表達式總結

一、基礎

基本語法

[接口聲明] = (參數)-> {代碼。。。};

具體使用

1.表達式必須和接口綁定使用,符合接口的方法聲明。
如某個接口:

public interface A {
    String get(int i);
}

聲明接口時:

A a  = new A() {
    @Override
    public String get(int i) {
        return "hello " + i;
    }
};

使用lambda

A la = (int i) -> {
    return "lambda " + i;
};

但如果一個接口有多個方法,則無法使用lambda表達式。如

public interface B {
    String get(int i);
    void set();
}

default和static方法除外

public interface A {
    String get(int i);

    default int fun1() {
        return 0;
    }

    static String fun2() {
        return "A";
    }
}

2.參數:可以是0到n個參數,具體根據綁定的接口而定,且參數類型可以不寫。

A la = (i) -> {
    return "lambda " + i;
};

3.返回值:如果代碼塊只有一行,可以沒有大括號。
沒有大括號時,不能用return關鍵字。
如果添加了大括號,或者有多行代碼,必須通過關鍵字return返回。

//可以這樣
A la2 = (i) -> "lambda " + i;
//也可以這樣
A la2 = (i) -> {
    return "lambda " + i;
};
//而不能這樣
A la2 = (i) -> return "lambda " + i;

java.util.function提供了大量的函數式接口供我們使用

Predicate,傳入T類型,返回boolean
Consumer,傳入T類型,消耗掉,返回void
function,傳入T類型,返回E類型
Supplier,傳入返回T類型
UnaryOperator,傳入T,返回T
BinaryOperator,傳入兩個T類型,返回T類型
emmm,記不住~~~

如Predicate
 Predicate<String> pre1 = (name) -> "admin".equals(name);
 System.out.println(pre1.test("admin") ? "管理員" : "普通用戶");

 打印結果:
 管理員

lambda對this關鍵字的優化

使用lambda表達式時,在表達式內部this代表的是該lambda表達式所屬的對象。
正常情況下,在接口內部使用this,該this指的是這個接口,而不是聲明該接口的對象(或者說該接口所屬的對象)

public class Test{
    String s1 = "全局變量";
    public void testLambda() {
        String s2 = "局部變量";
        new Thread(new Runnable() {
            @Override
            public void run() {
                String s3 = "內部變量";
                System.out.println(this.s1);//報錯!!!
                System.out.println(s2);
                System.out.println(s3);
            }
        }).start();
    }

    public static void main(String[] args) {
        new App().testLambda();
    }
}
public class Test {
    String s1 = "全局變量";
    public void testLambda() {
        String s2 = "局部變量";
        new Thread(() -> {
            String s3 = "內部變量";
            System.out.println(this.s1);//不報錯!!!
            System.out.println(s2);
            System.out.println(s3);

        }).start();
    }

    public static void main(String[] args) {
        new App().testLambda();
    }
}

打印結果:
全局變量
局部變量
內部變量

方法重載對lambda表達式的影響

當遇到重載方法時,如果方法中傳入的接口中的方法參數類型和返回值一樣,則無法使用lambda。如

public class Test {

    public static void main(String[] args) {
        test(() ->{//報錯!!!
            System.out.println("I1");
            return 1;
        });
    }
    //重載方法
    private static void test(A a) {
        a.printString();
    }
    private static void test(B b) {
        b.printInt();
    }

}

interface A {
    void printString();
}
interface B {
    void printInt();
}

二、lambda在集合中的應用

方法引用

1. 靜態方法、實例方法引用

以List.sort() 為例
實體類:

class Person {
    private String name;
    private int age;

    public static int compareByAge(Person p1, Person p2) {
        return p1.age - p2.age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    setter and getter...

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
數據源
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("Tom", 28));
        persons.add(new Person("Jack", 30));
        persons.add(new Person("Dav", 20));
使用內部類方式
        //使用內部類方式
        persons.sort(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int i = o1.getAge() - o2.getAge();
                return i;
            }
        });
使用lambda方式
        //使用lambda方式
        persons.sort((a, b) -> a.getAge() - b.getAge());
        persons.sort(Comparator.comparingInt(Person::getAge));
先在任意一個類中定義參數為(Person p1, Person p2),返回類型為 int 的靜態方法和普通方法
class PersonUtil {
    public int compareByAge(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }

    public static int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}
靜態方法引用,類名::靜態方法名
//靜態方法的引用,會默認將(Person, Person)參數傳遞給PersonUtil的compare方法
persons.sort(PersonUtil::compare);
實例方法引用,對象::普通方法名
//實例方法的引用
PersonUtil pu = new PersonUtil();
persons.sort(pu::compareByAge);
2. 構造方法引用

除了靜態方法引用和實例方法引用還有構造方法引用。

interface IPerson {
    //通過指定類型的構造方法初始化對象數據,
    //即:Person類中必須有(String name, int age)類型參數的構造方法。
    Person initPerson(String name, int age);
}

//構造方法的引用
IPerson ip = Person::new;
Person wang = ip.initPerson("wang", 25);

Stream

Stream解耦了對數據的各種操作,比起傳統的手動操作數據更方便。
例如:

List<String> list = new ArrayList<>();
list.add("abc");
list.add("adcd");
list.add("adcde");
list.add("adcdef");
//傳統方式獲取list中元素長度>=4的數據
List<String> result = new ArrayList<>();
for (String s : list) {
    if (s.length() >= 4) {
        result.add(s);
    }
}
System.out.println(result);
//使用Stream方式獲取list中元素長度>=4的數據
List<String> collect = list.stream().filter(s -> s.length() >= 4).collect(Collectors.toList());
System.out.println(collect);

打印結果:
[adcd, adcde, adcdef]
[adcd, adcde, adcdef]
Stream概述
/**
 * 1. 獲取Stream對象
 *      1.  從集合或數組中獲取[**]
 *          Collection.stream(),如list.stream()
 *          Collection.parallelStream()
 *          Arrays.stream()
 *      2.  BufferReader
 *          BufferReader.lines()
 *      3.  靜態方法
 *          java.util.stream.IntStream.range()..
 *          java.nio.file.Files.walk()..
 *      4.  自定義構建
 *          java.util.Spliterator
 *      5.  更多方式。。
 *          Random.ints()
 *          Pattern.splitAsStream()..
 * 2. 中間操作api
 *      操作結果是一個Stream,中間操作可以有一個或多個連續的中間操作,需要注意的是,中間操作只記錄操作方式,
 *      不做具體執行,直到借宿操作發生時,才做數據的最終執行。
 *      中間操作:就是業務邏輯處理。
 *      中間操作過程:
 *              無狀態:數據處理是,不搜前置中間操作的影響。
 *                      map/filter/peek/parallel/sequential/unordered
 *              有狀態:數據處理時,受前置中間操作的影響。
 *                      distinct/sorted/limit/skip
 * 3. 終結操作 | 結束操作{Terminal}
 * 需要注意:一個Stream對象,只能由一個Terminal操作,這個操作一旦發生,就會真實的處理數據。
 * 終結操作:
 *          非短路操作:當前的Stream對象必須處理完集合中所有數據才能得到結果。
 *                      forEach/forEachOrdered/toArray/reduce/collect/min/max/count/iterator
 *          短路操作:當前的Stream對象在處理過程中,一旦滿足某個條件,就可以得到結果。
 *                      anyMatch/allMatch/noneMatch/findFirst/findAnd等
 */

對比上面例子

list.stream()  //獲取Stream
.filter(s -> s.length() >= 4)  //中間操作,返回一個Stream對象
.collect(Collectors.toList());  //終結操作

Stream的獲取

//多個數據
Stream<String> stream1 = Stream.of("A", "B", "C");

//數組
String[] strArray = new String[]{"A", "B", "C"};
Stream<String> stream2 = Stream.of(strArray);

//列表
ArrayList<Object> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Stream<Object> stream3= list.stream();

//集合
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");
Stream<String> stream4 = set.stream();

//map
HashMap<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
Stream<Map.Entry<String, Integer>> stream5 = map.entrySet().stream();

Stream對象對于基本數據類型的封裝

// int / long / double
IntStream.of(new int[] {10, 20, 30}).forEach(System.out::println);
IntStream.range(1,5).forEach(System.out::println);
IntStream.rangeClosed(1,5).forEach(System.out::println);

從Stream中獲取指定的類型數據

Stream<String> stream1 = Stream.of("A", "B", "C");
//array
String[] arrayx = stream1.toArray(String[]::new);
//string
String stringx = stream1.collect(Collectors.joining());
//list
List<String> listx = stream1.collect(Collectors.toList());
//set
Set<String> setx = stream1.collect(Collectors.toSet());
//map
Map<String, String> mapx = stream1.collect(Collectors.toMap(x -> "key:" + x, y -> "val:" + y));
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。