一回顧與說明
經過前面發布的三章java8的博客,你就懂得了我們為什么要用Lamda表達式,Lamda表達式的原理與函數式接口的關系,從Lamda表達式到方法引用和構造引用。
想要學Stream流你必須對前面的知識熟悉並且掌握,今天我們來講一下Lamda表達式的進階學習,Stream流API。
二什么是Stream流
流想比大家都認識,比如食物的包裝過程,先要有個食物員提供食物,食物經過加工處理,添加調料,...,包裝,組裝。簡單的說普通的流就像工廠的流水線一樣。
Stream流是可以能夠用聲明的方式來操作集合(可以想象sql操作數據庫那樣),可以將其看作遍歷數據集的高級迭代器。在操作流的時候我們就可以將其比喻成工廠中的流水線。
三 流的優勢
流有什么優勢呢?流竟然是一種迭代器,那它與集合的for循環有什么區別,為什么我們要用流來迭代呢?
- 集合中存放的數據都是計算好的,我們用一次集合遍歷,必須有始有終,不能中斷。Stream流像視頻流一樣我們可以先加載一部分,看一部分,中途還能暫停中斷離開;相比之集合流更加靈活
- 流的迭代遍歷是一次性的,意味着一個流你只能迭代一次,完成迭代這個流就被消費掉。
- 流相比於for循環是內部迭代的,我們只要給出具體的函數操作流就ok,而for循環是外部迭代。
四 Stream流的操作過程
Stream流跟生產線上的流類式有提供源,操作,終止三個過程
常見的中間操作流:
常見的結束流:
五常見的StreamAPI
初始化車輛信息
public List<Car> InitCar(){
ArrayList<Car> carList = new ArrayList<>();
Car car1 = new Car("100", "black", "中國", 20);
Car car2 = new Car("101", "gray", "中國", 30);
Car car3 = new Car("102", "yello", "中國", 50);
Car car4 = new Car("103", "silvery", "英國", 20);
Car car5 = new Car("104", "red", "英國", 30);
carList.add(car1);
carList.add(car2);
carList.add(car3);
carList.add(car4);
carList.add(car5);
return carList;
}
1 篩選
filter函數就是過濾出流中我們需要的元素--中間操作
@Test
public void filterTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 篩選車輛時黑色的車
List<Car> result = cars.stream()
.filter(car -> car.getColor().equals("black"))
.collect(Collectors.toList());
//[Car(code=100, color=black, factory=中國, price=20.0)]
System.out.println(result);
}
2排序
sorted函數默認會升序排序元素--中間操縱
@Test
public void sortTest(){
int[] ints = {0, 5, 7, 6, 15, 13, 27};
Arrays.stream(ints).sorted().forEach(System.out::println);
}
3 去重
distinct去掉重復的元素--中間操作
@Test
public void distinctTest(){
int[] ints = {5,6,5,6,27};
// 5 6 27
Arrays.stream(ints).distinct().forEach(System.out::println);
}
4 截斷
limit函數限值流的元素--中間操作
@Test
public void limitTest(){
int[] ints = {5,6,5,6,27};
// 5 6
Arrays.stream(ints).limit(2).forEach(System.out::println);
}
5跳躍
skip函數跳過n個元素--中間操作
@Test
public void skipTest(){
int[] ints = {5,6,5,6,27};
// 27
Arrays.stream(ints).skip(4).forEach(System.out::println);
}
6映射
map是轉換函數,接受一個函數為參數,將其映射在每一個元素上,轉換成新的元素。--中間操作
@Test
public void mapTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 只獲得車的價格
cars.stream().limit(1)
.map(Car::getPrice)
.forEach(System.out::println);//20.0
}
7流的扁平化
flatMap函數能將中間多個流的內容合並為一個流。--中間操作
@Test
public void flatMapTest(){
String[] array = {"youku1327"};
// 存放的是一個個數組 [Ljava.lang.String;@61f3fbb8
Arrays.stream(array).map(s -> s.split(""))
.forEach(System.out::print);
// 將一個個數組流合並為一個流輸出:youku1327
Arrays.stream(array).map(s -> s.split(""))
.flatMap(Arrays::stream)
.forEach(System.out::print);
}
8任意匹配
anyMatch函數任意匹配到流中的一個元素返回真。---終止操作
@Test
public void anyMatchTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 任意匹配黃色的車
boolean yello = cars.stream()
.anyMatch(car -> car.getColor().equals("yello"));
System.out.println(yello);//true
}
9 完全匹配
allMatch函數完全匹配流中的元素返回真。--終止操作
@Test
public void allMatchTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 完全匹配黃色的車
boolean yello = cars.stream()
.allMatch(car -> car.getColor().equals("yello"));
System.out.println(yello);//false
}
10非匹配
noneMatch函數沒有匹配到流中的任意一個元素返回為真。------終止操作
@Test
public void noneMatchTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 不是youku1327這個顏色的車
boolean yello = cars.stream()
.noneMatch(car -> car.getColor().equals("youku1327"));
System.out.println(yello);//true
}
11任意尋找流中的一個元素
findAny函數任意查找流中的一個元素返回。---終止操作
@Test
public void findAnyTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 不是youku1327這個顏色的車
Optional<Car> anyCar = cars.stream().findAny();
Car car = anyCar.orElse(new Car("141", 50));
// Car(code=100, color=black, factory=中國, price=20.0)
System.out.println(car);
}
12 尋找流中的第一個元素
findFirst函數尋找流中的第一個元素。--------終止操作
@Test
public void findFirstTest(){
// 初始化車輛
List<Car> cars = carFunFactory.InitCar();
// 不是youku1327這個顏色的車
Optional<Car> anyCar = cars.stream().findFirst();
// Car(code=100, color=black, factory=中國, price=20.0)
System.out.println(anyCar.get());
}
13 歸約
reduce函數將前一個入參數和后一個入參進行操作后的值做為第下一次操作的前一個入參,以此類推。--終止操作
@Test
public void reduceTest(){
int[] ints = {3,4,5,};
int reduce = Arrays.stream(ints)
.reduce(0, (left, right) -> left + right);
// 求和 12
System.out.println(reduce);
OptionalInt max = Arrays.stream(ints).reduce(Integer::max);
// 求最大值 5
System.out.println(max.getAsInt());
OptionalInt min = Arrays.stream(ints).reduce(Integer::min);
// 求最小值 3
System.out.println(min.getAsInt());
}
14數值流
IntStream 、 DoubleStream 和LongStream ,分別將流中的元素特化為 int 、 long 和 double ,避免自動裝箱
。-----中間操作
@Test
public void numTest(){
int[] ints = {5,6,5,6};
// int流
IntStream intStream = Arrays.stream(ints);
// 6767愛看youku1327
intStream.mapToObj(value -> value+1).forEach(System.out::print);
System.out.println("愛看youku1327");
double[] doubles = {5,6,5,6};
// double流
DoubleStream doubleStream = Arrays.stream(doubles);
//5.06.05.06.0關注youku1327
doubleStream.forEach(System.out::print);
System.out.println("關注youku1327");
// long流
Long[] longs = {5L,6L,5L,6L};
Stream<Long> longStream = Arrays.stream(longs);
long count = longStream.count();
// 4
System.out.println(count);
}
15 流轉換
boxed函數將數值流轉為原始流。-----中間操作
@Test
public void streamSwapTest(){
int[] ints = {5,6,7};
// 將int流轉為原始流
Optional<Integer> first = Arrays.stream(ints).boxed().findFirst();
System.out.println(first.get());//5
// 2.23606797749979 2.449489742783178 2.6457513110645907
Arrays.stream(ints).boxed()
.mapToDouble(s ->Math.sqrt(s))
.forEach(System.out::println);
}
六 構建流
1 數值生成流
@Test
public void buildStreamByValue(){
Stream<String> stream = Stream.of("關", "注", "微", "信", "公", "眾", "號", ":", "youku1327", "謝謝");
//關注微信公眾號:youku1327謝謝
stream.map(StringUtils::join).forEach(System.out::print);
}
2 由數組創建流
@Test
public void skipTest(){
int[] ints = {5,6,5,6,27};
// 27
Arrays.stream(ints).skip(4).forEach(System.out::println);
}
3 由文件創建流
@Test
public void buildStreamByFile(){
try {
Stream<String> lines = Files.lines(Paths.get("C:\\mydata\\youku1327.txt"), Charset.defaultCharset());
lines.map(s -> s.split(""))
.flatMap(Arrays::stream)
.forEach(System.out::print);//youku1327
} catch (IOException e) {
e.printStackTrace();
}
}
4創建無限流
generate和iterate都是創建無限流,我們要約束一下,以免無線流一直創建元素。
@Test
public void buildStreamByIterate(){
long count = Stream.iterate(1, integer -> integer + 1)
.limit(100)
.count();
System.out.println(count);//100
}
七 致謝
觀看完這一篇stream流API操作基本就可以勝任平常工作中的各種場景,后面會繼續更新流的高級操作
最后推一波微信公眾號,有興趣學習的就關注吧。