一塊兒來學Java8(七)——Stream(上)

從Java8開始,新增了一個java.util.stream包,這個包下的類和接口用來處理集合中的元素,在這個包下面有一個Stream接口,咱們主要使用這個接口來對集合進行操做。java

建立Stream

首先來看下建立Stream有哪幾種方式。sql

使用Stream自帶的靜態方法生成Stream對象,常見的靜態方法有如下幾個:數組

  • Stream.of(T)
  • Stream.of(T... values)
  • Stream.generate(Supplier)
  • Stream.iterate(T, UnaryOperator)
  • Stream.empty()

如今來看下每一個靜態方法的做用iphone

Stream.of(T) & Stream.of(T... values)

Stream.of是由兩個重載方法組成,一個傳入單值,一個傳入數組函數

String[] arr = {"hello", "world"};
Stream streamArr = Stream.of(arr);

String str = "hello world";
Stream streamSingle = Stream.of(str);

Stream.generate & Stream.iterate

Stream.generate和Stream.iterate能夠用來生成具備多個元素的Stream,若是不加控制會一直生成下去,通常配合limit(n)使用學習

先來看下Stream.iteratecode

Stream<Integer> stream5 = Stream.iterate(0,  n-> n+1)
			.limit(5);
stream5.forEach(System.out::println);

打印對象

0
1
2
3
4

Stream.iterate方法第一參數設定一個初始值,第二個參數表示基於這個初始值,每次循環後返回一個新的值替換這個初始值。limit(5)表示循環5次結束,最後Stream中包含了5個元素。排序

再來看下Stream.generate接口

Stream.generate方法只有一個Supplier參數,意思是每次循環執行Supplier接口方法返回一個新的值,放入到Stream中,因爲Supplier是一個函數式接口,所以能夠直接寫成Lambda表達式

AtomicInteger i = new AtomicInteger();
Stream.generate(()-> {
	return i.getAndIncrement();
})
.limit(5)
.forEach(System.out::println);

上面的代碼一樣打印0~4。

除了Stream靜態方法以外,還可使用Collection接口中的stream()方法來生成Stream對象。

Collection<String> list = Arrays.asList("hello", "world");
Stream streamList = list.stream();

同理,只要是Collection接口的子類或實現類均可以使用stream()方法。

操做Stream

Stream中的方法有不少,大體概括以下表格所示:

方法 方法參數 返回類型 描述
filer Predicate<T> Stream<T> 過濾數據
distinct Stream<T> 去重
map Function<T, R> Stream<R> 返回新的數據
flatMap Function<T, R> Stream<T, Stream<R>> 返回新的數據,並作扁平化處理
sort Comparator<T> Stream<T> 對數據進行排序操做
limit long Stream<T> 截取前幾條數據
skip long Stream<T> 跳過幾條數據
anyMatch Predicate<T> boolean 匹配任意一條數據,若是匹配到返回true
noneMatch Predicate<T> boolean 若是沒有匹配到數據,返回true
allMatch Predicate<T> boolean 若是全部數據所有匹配到,返回true
findAny Optional<T> 返回任意一條數據
findFirst Optional<T> 返回第一條數據
count long 返回元素個數
forEach Consumer<T> void 遍歷元素,執行Consumer
collect Collector<T, A, R> R 元素收集
reduce BinaryOperator<T> Optional<T> 數據彙總

從方法的返回結果能夠看出,這些方法能夠分爲兩大類,一類是返回Stream對象,能夠繼續對Stream操做,這類方法也被稱之爲中間操做(Intermediate operations),另外一類是返回非Stream,結束操做,這類方法也被稱之爲中端操做(Terminal operations),這兩類方法每每一塊兒配合操做。

下面咱們挑選其中的幾個方法來演示它們的做用。

filter

filter方法用來篩選出咱們想要的數據,方法參數是一個Predicate接口,由於Predicate是一個函數式接口,咱們可使用Lambda表達式來寫。

Integer[] arr = { 1, 2, 3, 4, 5 };
long count = Stream.of(arr)
		.filter(i -> i % 2 == 0)
		.count();
System.out.println("偶數數量:" + count);

在這個例子中,咱們篩選出了偶數數字,而且統計出偶數的數量。若是要打印每一個偶數,可使用forEach方法

Stream.of(arr)
		.filter(i -> i % 2 == 0)
		.forEach(System.out::println);

打印:

2
4

若是要查找任意一個元素,可使用findAny

int num = Stream.of(arr)
		.filter(i -> i % 2 == 0)
		.findAny()
		.orElse(0);
System.out.println("findAny:" + num);

注意,findAny()返回的是一個Optional對象,由於有可能沒有找到數據,所以須要開發者本身處理沒有找到數據的狀況。同理findFirst也是返回一個Optional對象。

distinct

distinct方法會對元素進行去重操做,相似於SQL中的SELECT distinct xx

Stream.of(1,1,2,3,3,4)
	.distinct()
	.forEach(System.out::println)

打印

1
2
3
4

sorted

使用sorted方法能夠對元素進行排序操做

Stream.of(6,1,7,2,8,5)
	.sorted()
	.forEach(System.out::println);

打印

1
2
5
6
7
8

sorted()默認是從小到大排列,若是要從大到小降序,可使用.sorted(Comparator.reverseOrder())

Stream.of(6,1,7,2,8,5)
	.sorted(Comparator.reverseOrder())
	.forEach(System.out::println);

能夠看到,sorted方法容許傳入一個比較器Comparator讓開發者本身實現排序邏輯。下面是一個自定義Comparator例子:

@Data
@AllArgsConstructor
static class Goods {
	private String goodsName;
	private int price;
}

Stream.of(
		new Goods("iphoneX", 4000)
		, new Goods("mate30 pro", 5999)
		, new Goods("redmek20", 2999)
		)
.sorted((goods1, goods2) -> {
	return Integer.compare(goods1.getPrice(), goods2.getPrice());
})
.forEach(System.out::println);

這個列子演示了按商品價格從低到高排序。此處的sorted部分能夠簡化爲:.sorted(Comparator.comparing(Goods::getPrice))

map

map方法能夠返回一個新的數據對象,組成一個新的Stream。

List<Goods> list = Arrays.asList(
		new Goods("iphoneX", 4000)
		, new Goods("mate30 pro", 5999)
		, new Goods("redmek20", 2999)
		);
list.stream()
	.map(goods -> goods.getGoodsName())
	.forEach(System.out::println);

上面的示例演示的是從原有的商品對象中拿到商品名稱,而後組成一個新的List,其效果等同於

List<String> goodsNameList = new ArrayList<>(list.size());
for(Goods goods : list) {
	goodsNameList.add(goods.getGoodsName());
}

map方法通常配合collect()方法一塊兒使用

List<Goods> list = Arrays.asList(
        new Goods("iphoneX", 4000)
        , new Goods("mate30 pro", 5999)
        , new Goods("redmek20", 2999)
);
List<String> nameList = list.stream()
        .map(goods -> goods.getGoodsName())
        .collect(Collectors.toList());

collect(Collectors.toList())的意思是將Stream中的元素轉換成List

flatMap

flatMap()方法是map()方法的扁平化處理,與map不一樣的是,flatMap把返回Stream對象操做交給開發者本身處理。看下面的例子:

Stream<String[]> stream = Stream.of("I am Java", "hello world")
        .map(s -> s.split(" "));

這個例子的本意是想要將每一個字符串進行拆分,把單詞單獨放入到Stream中,因爲map返回的是一個字符串數組String[],所以獲得的Stream對象的泛型參數就是Stream<String[]>,而不是Stream<String>

解決辦法是使用flatMap:

Stream<String> stream2 = Stream.of("I am Java", "hello world")
                .flatMap(s -> Stream.of(s.split(" ")));
stream2.forEach(System.out::println);

打印:

I
am
Java
hello
world

綜合示例

下面來看一個綜合示例,演示的功能是:查詢商品名稱,價格大於3000,按價格降序

public class StreamTest3 {
    @Data
    @AllArgsConstructor
    static class Goods {
        private String goodsName;
        private int price;
    }

    public static void main(String[] args) {
        List<Goods> list = Arrays.asList(
                new Goods("iphoneX", 4000)
                , new Goods("mate30 pro", 5999)
                , new Goods("redmek20", 2999)
        );
        // 查詢商品名稱,價格大於3000,按價格降序
        List<String> nameList = list.stream()
                .filter(goods -> goods.getPrice() > 3000)
                .sorted(Comparator.comparing(Goods::getPrice).reversed())
                .map(Goods::getGoodsName)
                .collect(Collectors.toList());
        System.out.println(nameList);
    }
}

打印:[mate30 pro, iphoneX]

代碼對應的SQL爲:

SELECT goods_name FROM goods WHERE price > 3000 ORDER BY price DESC

小結

本篇講解了如何建立Stream以及Stream一些經常使用方法的使用方式,咱們將會在下一篇着重講解collect()reduce()的用法。

按期分享技術乾貨,一塊兒學習,一塊兒進步!

相關文章
相關標籤/搜索