java8 lambda和stream的理解


一、lambda表達式

語法:

(parameters) -> expression
或
(parameters) ->{ statements; }

parameters是參數,expression是表達式,statements是代碼塊。

lambda表達式,其實就是匿名函數。

->左側是方法參數,參數可以有多個。->右側是方法內容,也可以直接是方法的返回值。

比如 x->x+5,表示接收參數x,返回x+5。

(x, y) -> x + y ,表示接收參數x和y,返回x+y的和。

lambda表達式,可以作為其他方法的參數。

:: 雙冒號用法

可以通過 :: 來使用類的方法。

語法:

類名::方法名

比如 Integer::valueOf,就相當於Integer.valueOf()。

System.out::println,就相當於System.out.println();

Person::new,就相當於new Person();

有些lambda表達式,可以用雙冒號用法來表示。

比如 x->Integer.valueOf(x) ,可以寫成 Integer::valueOf ,

x->x!=null ,可以寫成 Objects::nonNull ,

person -> person.getName() ,可寫成 Person::getName .

創建對象

創建對象Worker,后續會用作示例,如下:

public class Worker {

    private String id;

    private Integer age;

    private String name;
    
    public Worker(String id, Integer age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    
    //getter()和setter()自行生成

二、forEach()

forEach() 方法迭代集合中的數據。

  • 遍歷List:
/**
 * 遍歷集合
 *
 */
public void forEachDemo() {
	List<String> list=Arrays.asList("abc","def","","123");
	list.forEach(System.out::println);
}
  • 遍歷Map:
public void foreachTest() {
    List<Worker> list = new ArrayList<>();
    list.add(new Worker("123",18,"lin"));
    list.add(new Worker("456",28,"chen"));
    list.add(new Worker("789",38,"wu"));
    Map<String, Integer> map = new HashMap<>();
    //forEach()內的方法參數為work,執行的操作是將Worker對象的id作為key,age作為value
    list.forEach(worker -> map.put(worker.getId(),worker.getAge()));
    //遍歷map,打印key和value
    // map.forEach((key,value)->System.out.println(key+","+value));
    map.forEach((key,value)-> {
            System.out.println(key+","+value);
            if ("456".equals(key)) {
                System.out.println("TargetValue:"+value);
            }
        });
}
  • 注意:

在forEach()中不能使用continue、break,即使使用return也不會終止lambda。
如下:

public void forEachContinueTest() {
        List<Worker> list = new ArrayList<>();
        list.add(new Worker("123",18,"lin"));
        list.add(new Worker("456",28,"chen"));
        list.add(new Worker("789",38,"wu"));
        Map<String, Integer> map = new HashMap<>();
        list.forEach(worker -> map.put(worker.getId(),worker.getAge()));
        map.forEach((key,value)->{
            System.out.println(key+","+value);
            if ("456".equals(key)) {
                System.out.println("Over");
                //在forEach()中使用continue會報錯"Continue outside of loop"
//                continue;   
                //在forEach()中使用return並不能中止lambda表達式
                return;      
            }
        });

    }

運行結果為:

123,18
456,28
Over
789,38

三、stream流

stream()流,可以非常方便地處理集合數據。包括filter()、map()、sorted()、forEach()等操作。

stream() − 為集合創建串行流。parallelStream() − 為集合創建並行流。

流的操作又分為:

(1)中間操作:filter(Predicate ), map(Function(T, R), limit, sorted(Comparator ), distinct,flatMap;

(2)終端操作:只有終端操作才能產生輸出,包括:allMatch, anyMatch, noneMatch, findAny, findFirst, forEach, collect, reduce, count

map()

  • map() 方法用於映射每個元素到對應的結果。
/**
 * 映射
 */
public void mapDemo(){
	List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
	// 獲取對應的平方數。distinct()用於去重。
	List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
	squaresList.forEach(System.out::println);
}
  • mapToInt()、mapToLong()用於轉換流的數據類型:
    mapToInt()將映射轉成int類型,轉化后還可以接上max(),min(),sum()等函數。
public void mapToIntDemo() {
	List<String> numberList= Arrays.asList("3", "2","2","3");
	//將集合中的字符串轉化數字,並進行加一操作,最后求和。
	int sum = numberList.stream().mapToInt(Integer::valueOf).map(x->x+1).sum();
	System.out.println(sum);
}

filter()

/**
 * 過濾
 */
public void filterDemo(){
	List<String> list=Arrays.asList("abc","def","","123");
	//篩選出不為空的數據
	List<String> filterList = list.stream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
	filterList.forEach(System.out::println);
}

如果要用filter過濾多個條件,可以如下表示:

比如要判斷集合中的任意對象person不為空,且personName也不為空:

List<Person> filterList = list.stream()
                              .filter(p-> (p!=null && p.getPersonName()!=null ))
                              .collect(Collectors.toList());

limit()

limit 方法用於獲取指定數量的流。

sorted()

sorted 方法用於對流進行排序。

public void sortedDemo() {
	List<Integer> list=Arrays.asList(1,3,5,7,2,4,6);
	List<Integer> numberList = list.stream().sorted().collect(Collectors.toList());
	numberList.forEach(System.out::println);

}

倒序輸出,示例如下:

public void sortedReverseDemo() {
	List<Integer> list=Arrays.asList(1,3,5,7,2,4,6);
	List<Integer> numberList = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
	numberList.forEach(System.out::println);
}

count()

/**
 * 計數
 */
public void countDemo() {
	List<String> list=Arrays.asList("abc","def","","123",null);
	//使用apache-common中的StringUtils,可以避免空指針
	long count = list.stream().filter(StringUtils::isNotEmpty).count();
	System.out.println(count);
}

collect()

collect() 可以將流轉化為集合以及字符串等其他形式。

  • collect(Collectors.toList()) : 表示將流轉化為List集合。
public void listStringtoInteger() {
    List<String> strList=new ArrayList<>();
    strList.add("1");
    strList.add("2");
    strList.add("abc");
    //將list轉化為流,然后過濾掉非數字的字符串,再將字符串轉化為數字,最后轉化回list。
    List<Integer> integerList = strList.stream().filter(StringUtils::isNumeric).map(Integer::valueOf).collect(Collectors.toList());
    integerList.forEach(System.out::println);
}
  • collect(Collectors.joining(",")):表示將流轉化為逗號分隔的字符串。

示例如下:

/**
 *  將集合轉化成符號分隔的字符串
 *
 */
public void collectJoiningDemo(){
	List<String> list=Arrays.asList("abc","def","","123");
//		String contents=String.join(",",list);
	//表示通過 ,號分隔
	String contents = list.stream().filter(StringUtils::isNotEmpty).collect(Collectors.joining(","));
	System.out.println(contents);
}

  • 還有將流轉化為Map的Collectors.toMap。

//以下的toMap(Worker::getId, Worker::getName)表示將流轉化為Map,鍵為Worker對象的id屬性,值為Worker對象的name屬性。
Map<String, String> map = list.stream().collect(Collectors.toMap(Worker::getId, Worker::getName));

Collectors.toMap的坑

在Collectors.toMap()中,要注意:
key不可重復,否則toMap()會報錯"Duplicate key"。
value不可為null,否則toMap()會報錯"空指針異常"。

public void toMapTest() {
        List<Worker> list = new ArrayList<>();
        list.add(new Worker("123",18,"lin"));
        list.add(new Worker("456",28,"chen"));
        list.add(new Worker("789",38,"wu"));
        //key不可重復,否則toMap()會報錯"Duplicate key"
//        list.add(new Worker("123",18,"li"));        
        //value不可為null,否則toMap()會報錯"空指針異常"
//        list.add(new Worker("000",18,null));          
        //以下的toMap(Worker::getId, Worker::getName)表示將流轉化為Map,鍵為Worker的id屬性,值為Worker的name屬性。
        Map<String, String> map = list.stream().collect(Collectors.toMap(Worker::getId, Worker::getName));
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey()+","+entry.getValue());
        }
    }

參考資料:https://www.jianshu.com/p/aeb21dea87e0

allMatch、anyMatch、noneMatch

用於匹配stream流中的數據。

allMatch: 都滿足條件才返回true;
anyMatch: 有一個滿足就返回true;
noneMatch: 都不滿足才返回true;

api如下:

boolean anyMatch(Predicate<? super T> predicate);

示例如下:

boolean b = Arrays.asList(1, 2, 3, 1).stream().anyMatch(p -> p > 2); //返回true

findAny、findFirst

查找,返回的結果是一個Optional對象。

Optional的理解,詳情見: https://www.cnblogs.com/expiator/p/12442629.html

api如下:

findAny:     Optional<T> findAny()
findFirst:     Optional<T> findFirst()

示例如下:

Arrays.asList(1, 2, 3, 4, 1).stream().filter(p -> p > 2).findAny() //輸出Optional[3]
Arrays.asList(1, 2, 3, 4, 1).stream().filter(p -> p > 2).findFirst() //輸出Optional[3]

reduce()

歸約操作,可以將流中的數據,按lambda表達式或者雙冒號用法反復地操作,最終得到一個值。

比如.reduce( (x,y) -> x + y) 會對流中所有的數據進行相加,得到結果。也可以寫成 .reduce(Integer::sum)。

reduce在求和、求最大最小值等方面都可以很方便,注意其返回的結果是一個Optional對象。

public class StreamReduce {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
        int sum = list.stream().map( x -> x*x ).reduce( (x,y) -> x + y).get();
        System.out.println(sum);
      
//          傳統的代碼表現方式如下:
//          List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
//          int sum = 0;
//          for(Integer n : list) {
//              int x = n * n;
//              sum = sum + x;
//          }
//          System.out.println(sum);

    }
}

    

參考資料:
https://www.cnblogs.com/whuxz/p/9570613.html


免責聲明!

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



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