Java 8 API添加了一個(gè)新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數(shù)據(jù)。
Stream 使用一種類似用 SQL 語(yǔ)句從數(shù)據(jù)庫(kù)查詢數(shù)據(jù)的直觀方式來(lái)提供一種對(duì) Java 集合運(yùn)算和表達(dá)的高階抽象。
Stream API可以極大提高Java程序員的生產(chǎn)力,讓程序員寫(xiě)出高效率、干凈、簡(jiǎn)潔的代碼。
這種風(fēng)格將要處理的元素集合看作一種流, 流在管道中傳輸, 并且可以在管道的節(jié)點(diǎn)上進(jìn)行處理, 比如篩選, 排序,聚合等。
元素流在管道中經(jīng)過(guò)中間操作(intermediate operation)的處理,最后由最終操作(terminal operation)得到前面處理的結(jié)果
生成流
在 Java 8 中, 集合接口有兩個(gè)方法來(lái)生成流:
stream() ? 為集合創(chuàng)建串行流。
parallelStream() ? 為集合創(chuàng)建并行流。
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
forEach
Stream 提供了新的方法 'forEach' 來(lái)迭代流中的每個(gè)數(shù)據(jù)。以下代碼片段使用 forEach 輸出了10個(gè)隨機(jī)數(shù):
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map
map 方法用于映射每個(gè)元素到對(duì)應(yīng)的結(jié)果,以下代碼片段使用 map 輸出了元素對(duì)應(yīng)的平方數(shù):
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 獲取對(duì)應(yīng)的平方數(shù)
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
filter 方法用于通過(guò)設(shè)置的條件過(guò)濾出元素。以下代碼片段使用 filter 方法過(guò)濾出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數(shù)量
int count = strings.stream().filter(string -> string.isEmpty()).count();
limit
limit 方法用于獲取指定數(shù)量的流。 以下代碼片段使用 limit 方法打印出 10 條數(shù)據(jù):
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted
sorted 方法用于對(duì)流進(jìn)行排序。以下代碼片段使用 sorted 方法對(duì)輸出的 10 個(gè)隨機(jī)數(shù)進(jìn)行排序:
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
并行(parallel)程序
parallelStream 是流并行處理程序的代替方法。以下實(shí)例我們使用 parallelStream 來(lái)輸出空字符串的數(shù)量:
@Test
public void parallelTest() {
List<Integer> integers = new ArrayList<>();
List<Integer> integerss = new ArrayList<>();
new Random().ints(32000000).forEach(integers::add);
new Random().ints(32000000).forEach(integerss::add);
long l = System.currentTimeMillis();
long count = integers.parallelStream().filter(a -> a > 0).count();
print.accept("并行統(tǒng)計(jì)耗時(shí):" + (System.currentTimeMillis() - l) + ",大于0 的數(shù)有:" + count);
long y = System.currentTimeMillis();
long count1 = integerss.stream().filter(a -> a > 0).count();
print.accept("串行統(tǒng)計(jì)耗時(shí):" + (System.currentTimeMillis() - y) + ",大于0 的數(shù)有:" + count1);
}
輸出結(jié)果:
并行統(tǒng)計(jì)耗時(shí):120,大于0 的數(shù)有:16002129
串行統(tǒng)計(jì)耗時(shí):261,大于0 的數(shù)有:16005320
我們可以很容易的在順序運(yùn)行和并行直接切換。
Collectors
Collectors 類實(shí)現(xiàn)了很多歸約操作,例如將流轉(zhuǎn)換成集合和聚合元素。Collectors 可用于返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("篩選列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
統(tǒng)計(jì)
另外,一些產(chǎn)生統(tǒng)計(jì)結(jié)果的收集器也非常有用。它們主要用于int、double、long等基本類型上,它們可以用來(lái)產(chǎn)生類似如下的統(tǒng)計(jì)結(jié)果。
List<Integer> integers = Arrays.asList(1, 2, 5, 7, 6, 8, 11, 33, 52, 78);
IntSummaryStatistics intSummaryStatistics = integers.stream().mapToInt(x -> x).summaryStatistics();
print.accept(intSummaryStatistics.getMax());
print.accept(intSummaryStatistics.getCount());
print.accept(intSummaryStatistics.getAverage());
intSummaryStatistics.getAverage();