天天看點

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

一:Lambda 表達式

😀Lambda表達式的标準格式:由三部分組成

  • 1 : 一些參數
  • 2 : 一個箭頭
  • 3 : 一段代碼

格式:

( 參數清單 ) -> { 一些重寫方法的代碼 }

說明:

  • () : 接口中抽象方法的參數清單,沒有參數,就空着;有參數就寫出參數,多個參數使用逗号分隔
  • -> : 傳遞的意思,把參數傳遞給方法體 { }
  • { } : 重寫接口的抽象方法的方法體

簡寫Lambda表達式格式:

  • 1:(參數清單):括号中參數清單的資料類型 可以省略不寫
  • 2:(參數清單):括号中的參數如果隻有一個,那麼類型 和 ( ) 都可以省略
  • 3:{代碼}:如果 { }中的代碼隻有一行,無論是否有傳回值,都可以省略 { }, return ,分号
  • 注意事項:如果要省略 { }, return ,分号 ,必須一起省略,否則都不能省略

🤭光說不練 假把式 上代碼

使用Lambda表達式建立線程

之前我們使用匿名内部類建立線程是這樣子滴~

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

使用Lambda表達式替換匿名内部類實作 建立多線程

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

還可以再簡寫

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

Lambda表達式的優化:

😀1、方法引用

定義一個列印的函數式接口

//定義一個列印的函數式接口
@FunctionalInterface
interface Printable{
	//列印字元串的抽象方法
	public abstract void print(String s);
} 
           

Main方法

public class Demo1Print {
	/*方法參數傳遞Printable接口,對字元串列印輸出
	 * */
	public static void printString(Printable p) {
		p.print("I Love Java");
	}
	public static void main(String[] args) {
		printString(s->System.out.println(s));
/*分析;Lambda表達式的目的,列印參數傳遞的字元串
 * 把s傳給了System.out對象,調用out中的方法pritnln(),對字元串進行輸出
 * 注意:
 * 此時的 System.out對象是存在的,println()方法也是存在的
 * 我們可以使用方法引用來優化Lambda表達式,使用System.out對象直接調用println()方法
 * 格式:		對象::方法
 * 雙冒号為 引用運算符,它所在的表達式被稱為方法引用
 * */
		printString(System.out::println);
	}

}
           

😀2、通過對象名 引用成員方法

使用前提:對象名 和 成員方法 已經存在 才可以使用 對象名 來引用 成員方法

注意:如果類中的方法是靜态的 就無法使用對象調用 直接用類名 引用 靜态成員方法

練習
public class Demo2_ObjectMethodReference {
	public static void printString(Printable p) {
		p.print("java");
	}
	public static void main(String[] args) {
		//調用printString方法,方法的參數Printable是一個函數式接口,是以可以傳遞Lambda表達式
		printString((s)->{
			//建立MethodFer對象
			MethodFer mf = new MethodFer();
			//使用MethodFer建立的對象 調用 該類中的方法printUpperCase
			mf.printUpperCase(s);	//輸出JAVA
		});
		//方法引用(優化)
		MethodFer mf2 = new MethodFer();
		printString(mf2::printUpperCase);	//輸出JAVA
		//或者
		printString(new MethodFer()::printUpperCase); //輸出JAVA
		/*
		 * printString(MethodFer::printUpperCase);
		 * Cannot make a static reference to the non-static method
		 *  printUpperCase(String) from the type MethodFer
		 */
		
		//通過類 引用 靜态成員方法
		printString(MethodFer::printLowerCase); //輸出java
	}
}
class MethodFer{
	public void printUpperCase(String str) {
		System.out.println(str.toUpperCase());
	}
	public static void printLowerCase(String str) {
		System.out.println(str.toLowerCase());
	}
}
           

😀3、通過類名引用靜态成員方法

比如:類Math 中的abs方法是靜态方法

前提:

類已經存在,靜态成員方法也存在, 就可以直接通過類型引用靜态成員方法

測試
public class Demo3_StaticMethodReference {

	public static int calcator(int num,Calc c) {
		return c.calcABS(num);
	}
	public static void main(String[] args) {
		int num = calcator(-10,n->Math.abs(n));
		System.out.println(num);
		/*使用方法引用來優化Lambda表達式
		 * Math類是存在的 abs方法也是存在的
		 * */
		int num2 = calcator(-20,Math::abs);
		System.out.println(num2);
	}

}
@FunctionalInterface
interface Calc{
	public abstract int calcABS(int num);
}
           

😀4、通過super 引用父類的成員方法,通過this 引用本類的成員方法

public class Demo4_Super_this_MethodReference {

	public static void main(String[] args) {
			Man man = new Man();
			man.show1();
			man.show2();
	}

}
//定義一個父類
class Human{
	//定義sayHello方法
	public void Say() {
		System.out.println("Say Hello! I am Father");
	}
}
//定義一個子類
class Man extends Human{
	//重寫父類sayHello方法
	public void Say() {
		System.out.println("Say Hi! I am son");
	}
	//定義一個方法 參數傳遞Greetable接口
	public void method(Greetable g) {
		g.greet();
	}
	//
	public void show1() {
		//調用method方法,方法的參數Greetable是一個函數式接口,是以可以傳遞Lambda表達式
//		method(()->{
//			//建立父類對象
//			Human h = new Human();
//			//調用父類的sayHello方法
//			h.Say();
//		});
		//因為有子父類關系 是以存在關鍵字super 代表父類 可以直接使用super調用父類的方法
//		method(()->{
//			super.Say();
//			});
		
/*繼續優化  既然 可以直接使用super調用父類的方法
 * 那麼就可以使用super引用類的成員方法 
 * 因為super是已經存在的 Say方法是已經存在的 
 * 是以可以直接使用super引用父類的Say方法
*/		method(super::Say);
	}
	public void show2() {
		//調用method方法,方法的參數Greetable是一個函數式接口,是以可以傳遞Lambda表達式
//		method(()->{
//			//建立本類對象
//			Man man = new Man();
//			//通過本類對象 調用本類的成員方法
//			man.Say();
//		});
		//關鍵字this 代表本類 可以直接使用this調用本類的方法
//		method(()->{
//			this.Say();
//		});
		//繼續優化 使用this 引用本類方法
		method(this::Say);
	}
}
//定義一個見面的函數式接口
@FunctionalInterface
interface Greetable{
	public abstract void greet();
}
           

😀5、通過構造器 引用成員方法

public class Demo5_ConstructorMethodReference {
	//定義一個方法 參數傳遞 姓名 和create接口
	public static Person getName(String n,Create c) {
		return c.create(n);
	}
	public static void main(String[] args) {
		//調用getName方法
//		Person name = getName("神廚小福貴",(s)->{
//			return new Person(s);
//		});
//		System.out.println(name);
		
		/*使用方法引用優化Lambda表達式
		 * 構造方法 new Person(String name); 已知
		 * 建立對象 new 已知
		 * 就可以使用Person 引用new 建立對象
		 * */
		Person name = getName("比卡丘",Person::new);
		System.out.println(name);
		
	}
	
}
//定義一個函數式接口
@FunctionalInterface
interface Create{
	//方法傳回值為Person 因為要傳回建立的對象
	public abstract Person create(String name);
}
//定義一個類
class Person{
	private String name;

	public Person(String name) {
		super();
		this.name = name;
	}

	public Person() {
		super();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + "]";
	}
}
           

😀6、數組的構造器引用

public class Demo6_ArrayMethodReference {
	//定義一個傳回數組的方法 參數傳遞 數組的長度 和接口
	public static int[] getArr(int len,CreateArr c) {
		return c.create(len);
	}
	
	public static void main(String[] args) {
		//調用getArr方法 
		int[] arr1 = getArr(10,L->new int[L]);
		System.out.println(Arrays.toString(arr1));
		System.out.println(arr1.length);
		/*使用方法引用優化 Lambda表達式
		 * 已知 數組類型 和數組建立方式
		 * int[]引用new,根據參數傳遞的長度來建立數組
		 * */
		int[] arr2 = getArr(20,int[]::new);
		System.out.println(Arrays.toString(arr2));
		System.out.println(arr2.length);
	}

}
//定義一個函數式接口
@FunctionalInterface
interface CreateArr{
	//定義一個建立int類型數組的抽象方法 傳回值為int[]
	public abstract int[] create(int len);
}
           

二:鍊式程式設計

思想:

是将多個操作(多行代碼)通過點号

.

連結在一起成為一句代碼,使代碼可讀性好。a(1).b(2).c(3)

下面的函數式程式設計就是用的這種風格

list.stream().filter(str->str.startsWith("李")).forEach(str->System.out.println(str));

三:常用的函數式接口

定義:有且隻有一個抽象方法的接口,稱之為函數式接口

當然接口中可以包含其他的方法( 預設,靜态,私有)

函數式接口的使用:

一般可以作為方法的參數和傳回值類型

函數式接口作為 方法的參數 的執行個體

java.lang.Runnable接口就是一個函數式接口

  • 假設有一個startThread方法使用該接口作為參數,那麼就可以使用Lambda表達式進行傳參
  • 這種情況其實跟Thread類的構造方法參數為Runnable沒有本質差別
public class RunnableDemo {
	//定義一個方法startThread 方法的參數使用 函數式接口Runnable
	public static void startThread(Runnable run) {
		//開啟多線程
		new Thread(run) {}.start();
	}
	public static void main(String[] args) {
		
		//調用startThread方法,方法的參數是一個接口,那麼我們可以傳遞這個接口的匿名内部類(或實作類)
		startThread(new Runnable() {
			public void run() {
				System.out.println(Thread.currentThread().getName()+" --> "+"線程開啟");
			}
		});
		//調用startThread方法,方法的參數是一個函數式接口,使用Lambda表達式進行傳參
		startThread( ()->{
		System.out.println(Thread.currentThread().getName()+" --> "+"線程開啟");
		});
		//Lambda表達式優化版本 省略 {} 和 ;
		startThread( ()->System.out.println(Thread.currentThread().getName()+" --> "+"線程開啟"));
	}

}

           
函數式接口作為 傳回值類型 的執行個體
  • 當一個方法的傳回值類型是一個函數式接口,那麼就可以直接傳回一個Lambda表達式
  • 當需要通過一個方法來擷取一個java.util.Comparator接口類型的對象作為排序器時,就可以調用該方法擷取
public class ComparatorDemo {
	//定義一個方法,方法的傳回值類型使用函數式接口Comparator
	public static Comparator<String> getComparator1(){
		//方法的傳回值類型是一個接口,那麼我們可以傳回這個接口的匿名内部類
		return new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				//按照字元串的降序排序
				return o2.length()-o1.length();
			}
		};
	}
	//改進版本		方法的傳回值類型是一個函數式接口,是以我們可以傳回一個Lambda表達式
	public static Comparator<String> getComparator2(){
		return (String o1,String o2)->{
			//使用字元串的降序排序
			return o2.length()-o1.length();
		};
	}
	//Lambda表達式優化版本
	public static Comparator<String> getComparator3(){
		return (o1, o2)-> o2.length()-o1.length();
	}
	
	
	public static void main(String[] args) {
		//建立一個字元串數組
		String[] arr = {"aaa","ccccc","bbbb"};
		//排序前
		System.out.println("排序前的數組:");
		System.out.println(Arrays.toString(arr));
		//進行升序排序
		Arrays.sort(arr);
		System.out.println("預設升序排序後的數組:");
		System.out.println(Arrays.toString(arr));
		//進行降序排序
		Arrays.sort(arr,getComparator3());
		System.out.println("降序排序後的數組:");
		System.out.println(Arrays.toString(arr));
	}

}

           
運作結果
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

這個包就包含了所有的函數式接口

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

該包下有許多接口,其中 主要的是這四個接口

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

1、java.util.function.Function<T , R>接口

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

根據一個類型的資料得到另一個類型的資料,前者 為前置條件 後者 為後置條件

Function接口中最主要的抽象方法為:

R apply(T t),根據類型T的參數擷取類型R的結果,andThen():用來進行組合操作

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
題目:将String 轉換為Integer

方法:

/*方法參數傳遞一個字元串類型的整數,和一個Function接口,泛型使用<String,Integer>
	 * 使用Function接口中的方法apply,把字元串類型的整數,轉換為Integer類型的整數
	 * */
	public static void method(String str,Function<String,Integer> fun) {
		int num = fun.apply(str);
		num+=100;
		System.out.println(num+0);
	}
           

main:

// 輸出 234
		method("123",new Function<String,Integer>(){
			@Override
			public Integer apply(String t) {
				return Integer.parseInt(t);
			}
		});
//使用Lambda表達式簡化
		method("234",str-> Integer.parseInt(str));
           
題目:把String類型的“123” 轉換為Integer類型的整數,再加10 ,再轉為String 使用 andThen

方法:

public static void method(String str,Function<String,Integer> fun1,Function<Integer,String> fun2) {
		/*	分兩步操作	
		int num = fun1.apply(str);
		str = fun2.apply(num);
		System.out.println(str);
		*/
		//使用andThen合成一步
		String app = fun1.andThen(fun2).apply(str);
		System.out.println(app+0);
	}
           

main:

2、java.util.function.Supplier 接口

僅包含一個無參方法

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
  • T get() 用來擷取一個泛型參數指定類型的對象資料
  • Supplier 接口被稱之為生産型接口(供應商接口)
  • 指定接口的泛型是什麼類型,那麼接口中的get方法就會生産什麼類型的資料
練習
public class SupplierDemo1 {
	//定義一個方法,方法的參數傳遞Supplier<T>接口,泛型執行String,get方法就會傳回一個String
	public static String getString(Supplier<String> sup) {
		return sup.get();
	}
	public static void main(String[] args) {
		System.out.println(getString( ()->{ return "光頭強";}));
		System.out.println(getString( ()->  "天才威"));
	}

}
           

題目:求數組元素的最大值:

使用Supplier接口作為方法參數類型,通過Lambda表達式求出int數組的最大值

public class SupplierDemo_GetArrMax {
	public static int getMax(Supplier<Integer> sup) {
		return sup.get();
	}
	public static void main(String[] args) {
		//定義一個整型數組
		int[] arr = {1,8,5,9,2,55,11,77,66};
		//調用getMax方法,使用Supplier接口作為方法參數類型
		//通過Lambda表達式求出int數組的最大值
		int maxNum = getMax( ()->{ 
			//定義一個變量存放數組中第一個數
			int num = arr[0];
			//循環查找
			for (int i : arr) {
				if(i>num)
					num = i;
			}
			return num;
		});
		System.out.println("數組中最大值為:"+maxNum);
	}

}
           

3、java.util.function.Predicate 接口

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

作用:對某種資料類型的資料進行判斷,結果傳回一個boolean值

Predicate接口中包含一個抽象方法:

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

boolean test(T t):用來對指定資料類型資料進行判斷的方法

  • 結果:
    • 符合條件:傳回true
    • 不符合條件:傳回false
練習
public class PredicateDemo {
	/*
	 * 定義一個方法
	 * 參數傳遞一個String類型的字元串
	 * 傳遞一個Predicate接口,泛型使用String
	 * 使用Predicate中的方法test對字元串進行判斷,并把判斷結果傳回
	 * */
	public static boolean method(String str,Predicate<String> pre) {
		return pre.test(str);
		
	}
	public static void main(String[] args) {
		//如果字元串長度大于五則 傳回true
		System.out.println(method("absafjsdf",(str)->{ return str.length()>5;}));
		System.out.println(method("abc",str-> str.length()>5 ));
	}

}
           
其他方法測試
public class PredicateDemo {
	//and執行個體	條件必須都滿足 相當于&&
	public static boolean checkingAnd(String str,Predicate<String> p1,Predicate<String> p2) {
//		return p1.test(str) && p2.test(str);
		return p1.and(p2).test(str);
	}
	//or執行個體  條件滿足一個即可 相當于 ||
	public static boolean checkingOr(String str,Predicate<String> p1,Predicate<String> p2) {
//		return p1.test(str) || p2.test(str);
		return p1.or(p2).test(str);
	}
	//negate表示取反 即為!
	public static boolean checkingNegate(String str,Predicate<String> p1) {
//		return !p1.test(str);
		return p1.negate().test(str);
	}
	public static void main(String[] args) {
		//And執行個體 true
		System.out.println(checkingAnd("ABFDFD",str->str.length()>5 , str->str.contains("A")));
		//Or執行個體 true
		System.out.println(checkingOr("ABFDFD",str->str.length()>10 , str->str.contains("A")));
		//Negate執行個體 false
		System.out.println(checkingNegate("adadad",str->str.length()>5));
	}

}
           

4、java.util.function.Consumer 接口

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

正好與Supplier接口相反,它不是生産一個資料,而是消費一個資料,其資料類型由泛型決定

  • Consumer接口中包含抽象方法 void accept( T t),意為消費一個指定泛型的資料
  • Consumer接口是一個消費型接口,泛型指定什麼類型,就可以使用accpet方法消費什麼類型的資料
  • 至于具體如何消費( 使用 ),需要我們自定義( 輸出,計算。。。)
    JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
練習
public class ConsumerDemo {
	/*定義一個方法	方法的參數傳遞一個字元串的姓名
	 * 方法的參數傳遞Consumer接口,泛型使用String
	 * 可以使用Consumer接口消費字元串的姓名
	 * */
	public static void consumerName(String name,Consumer<String> con) {
		 	con.accept(name);
	}
	public static void main(String[] args) {
		//使用匿名内部類
		consumerName("光頭強",new Consumer<String>() {
			public void accept(String t) {
				System.out.println(t);
			}
		});
		//因為此接口為 函數式接口 是以可以使用Lambda表達式
		// (String t )->{ System.out.println(t); }
		consumerName("天才威", t->System.out.println(t));
		
		//實作字元串反轉輸出
		consumerName("翠花",t-> System.out.println(new StringBuffer(t).reverse()) );
	}
}
           

Consumer接口的預設方法addThen

作用:需要兩個Consumer接口,可以把兩個Consumer接口組合到一起,再對資料進行消費

例如:

Consumer con1

Consumer con2

String s = “Hello”;

con1.accpet(s);

con2.accpet(s);

  • 改善:連接配接兩個Consumer接口,再進行消費
  • con1.addThen(con2).accpet(s); 誰寫前邊誰先消費
public class ConsumerDemo {
	//定義一個方法,方法的參數傳遞一個字元串和兩個Consumer接口,接口泛型使用字元串類型
	public static void method(String str,Consumer<String> con1,Consumer<String> con2) {
		con1.accept(str);
		con2.accept(str);
	}
	public static void method2(String str,Consumer<String> con1,Consumer<String> con2) {
		con1.andThen(con2).accept(str);
	}
	public static void main(String[] args) {
		//調用method方法,傳遞一個字元串,兩個Lambda表達式
		method("I am CSNZ",t->System.out.println(t.toUpperCase()),t->System.out.println(t.toLowerCase()));
		method2("I am CSNZ",t->System.out.println(t.toUpperCase()),t->System.out.println(t.toLowerCase()));
	}

}
           

題目:字元串數組中存有多條資訊,按照格式:“姓名:xx。性别:xx。”列印

使用兩個Consumer接口 最後andThen

public static void print(String[] a,Consumer<String> c1,Consumer<String> c2) {
		for (String str : a) {
			c1.andThen(c2).accept(str);
		}
	}
	public static void main(String[] args) {
		//定義一個字元串數組
		String[] arr = {"迪麗熱巴,女","古力娜紮,女","馬兒紮哈,男"};
		print(arr,(str)->{
			System.out.print("姓名:"+str.split(",")[0]+"。");
		},(str)->{
			System.out.print("性别:"+str.split(",")[1]+"。\n");
		});
	}	
}
           
執行結果:
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

四:Stream流式計算

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

java.util.stream.Stream 是java 1.8 新加入的最常用接口。(這并不是一個函數式接口,裡面不止一個抽象方法)

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

擷取一個流的方式:

所有的Collection集合都可以通過stream的預設方法擷取流

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

Stream接口的靜态方法of可以擷取可變長參數(底層即數組)對應的流

JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算

參數是一個可變參數,那麼我們就可以傳遞一個數組

練習
public class StreamDemo {
	public static void main(String[] args) {
		//把集合轉換為stream
		List<String> arrayList = new ArrayList<String>();
		Stream<String> stream1 = arrayList.stream();
		
		Set<String> hashset = new HashSet<>();
		Stream<String> stream2 = hashset.stream();
		
		
		//如果是Map集合的話(雙列集合)
		Map<String,String> hashMap = new HashMap<String,String>();
		
		//擷取鍵,存儲到一個set集合中,再轉換成流
		Set<String> keySet = hashMap.keySet();
		Stream<String> stream3 = keySet.stream();
		//擷取值,存儲到一個Collection集合中,再轉換成流
		Collection<String> values = hashMap.values();
		Stream<String> stream4 = values.stream();
		//擷取鍵值對(鍵與值的映射關系 entrySet)
		Set<Entry<String, String>> entrySet = hashMap.entrySet();
		Stream<Entry<String, String>> stream5 = entrySet.stream();
		
		
		//把數組轉換為Stream流
		Stream<Integer> stream6 = Stream.of(1,2,3,4,5);
		//可變長參數可傳遞數組
		int[] arr1 = {666,7,888};
		Stream<int[]> stream7 = Stream.of(arr1);
		Integer[] arr2 = {666,7,888};
		Stream<Integer> stream8 = Stream.of(arr2);
		String[] arr3 = {"a","bb","ccc"};
		Stream<String> stream9 = Stream.of(arr3);
		
	}
}
           
Stream流中常用方法 forEach
  • void forEach( Consumer <? super T> action);
  • 該方法接收一個Consumer接口函數,會将每一個流元素交給該函數處理
  • Consumer接口是一個消費型的函數式接口,可以傳遞Lambda表達式進行消費
  • Consumer中的抽象方法
    • void accept(T t);
  • forEach:即周遊流中的資料 是一個終結方法 周遊之後就不能調用stream流中的其他方法
public static void method1() {
		//建立一個Stream流
		Stream<Integer> stream1 = Stream.of(1,6,4,2,8);
		//使用Stream流中的方法forEach對流中的資料進行周遊
		stream1.forEach( str->System.out.println(str));
	}
           
Stream流中的常用方法filter:用于對Stream流中的資料進行過濾
  • Stream filter( Predicate<? super T> pre);
  • filter方法的參數是一個函數式接口,是以可以傳遞Lambda表達式,對資料進行過濾
  • Predicate中的抽象方法
    • boolean test(T t);
public static void method2() {
		//建立一個流
		Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
		//對流中的資料進行過濾 隻要偶數
		Stream<Integer> stream3 = stream2.filter(num->num%2==0);
		//對新的流進行周遊
		stream3.forEach(num->System.out.println(num));
	}
           
如果需要将流中資料映射到另一個流中,可以使用map方法
  • Stream map(Function<? super T, ? extends R> mapper);
  • 該接口需要一個Function函數式接口參數,可以将目前流中的T類型資料轉換為另一種R類型的資料
  • Function中的抽象方法
    • R apply(T t);
public static void method3() {
		//建立一個流
		Stream<String> stream1 = Stream.of("1","2","3","4","5");
		//将字元串轉換為整數類型
		Stream<Integer> stream2 = stream1.map(str->Integer.parseInt(str));
		stream2.forEach(num->System.out.println(num));
	}
           
Stream流中的常用方法:count:用于統計 流中元素個數
  • 是一個終結方法,傳回值是一個long類型的整數,是以在這之後無法調用其他的方法
public static void method4() {
		//建立一個流
		Stream<String> stream1 = Stream.of("1","2","3","4","5");
		long count = stream1.count();
		System.out.println(count);
	}
           
Stream流中的常用方法:limit:用于截取流中的元素,隻取前n個
  • Stream limit(long maxSize):
    • 參數是一個long型,如果集合目前長度大于參數則進行截取,否則不進行操作
  • limit方法是一個延遲方法,對流進行截取,傳回一個新的流,可以繼續調用流中的其他方法
public static void method5() {
		//建立一個流
		Stream<String> stream1 = Stream.of("火花","水藍籃","喵喵","少林呱呱","邪惡玄武");
		//對流中的元素進行截取
		Stream<String> stream2 = stream1.limit(3);
		//對截取的流進行周遊
		stream2.forEach(str->System.out.println(str));
	}
           
Stream流中的常用方法:skip:用于跳過元素
  • Stream skip(long n);
  • 如果流的目前長度大于n,則跳過前n個,否則會得到一個長度為0的流
public static void method6() {
		//建立一個流
		Stream<String> stream1 = Stream.of("火花","水藍籃","喵喵","少林呱呱","邪惡玄武");
		//對流進行跳過截取
		Stream<String> stream2 = stream1.skip(3);
		//對截取的流進行周遊
		stream2.forEach(str->System.out.println(str));
	}
           
Stream流中的常用方法:concat:用于把流組合到一起
  • static Stream concat(Stream <? extends T> a , Stream<? extends T> b)
public static void method7() {
		//建立一個流
		Stream<String> stream1 = Stream.of("火花","水藍籃","喵喵","少林呱呱","邪惡玄武");
		//建立另一個流
		Stream<String> stream2 = Stream.of("1","2","3","4","5");
		//将兩個流進行合并
		Stream<String> stream3 = Stream.concat(stream1, stream2);
		//周遊合并的流
		stream3.forEach(str->System.out.println(str));
	}
           
執行結果:
JDK8新特性 2W字總結的硬核知識一:Lambda 表達式二:鍊式程式設計三:常用的函數式接口四:Stream流式計算
題目:使用stream流對數組中的元素進行篩選周遊
public class Stream_List_demo {

	public static void main(String[] args) {
		//建立一個存儲元素的集合
		ArrayList<String> list = new ArrayList<>();
		list.add("李白");
		list.add("李黑");
		list.add("白黑");
		list.add("黑白");
		list.add("李黑白");
		
		/*普通方法篩選和周遊
		ArrayList<String> list2 = new ArrayList<>();
		for(String s:list) {
			if(s.startsWith("李") && s.length()==2) {
				list2.add(s);
			}
		}
		for (String str : list2) {
			System.out.println(str);
		}
		*/
		
		//使用stream流篩選周遊 結合函數式程式設計
		list.stream().filter(str->str.startsWith("李"))
		.filter(str->str.length()==2)
		.forEach(str->System.out.println(str));
	}
}
           

Stream流的特點:

  • 它屬于管道流,隻能被消費(使用)一次
  • 第一個Stream流調用完畢後,資料就會傳到下一個Stream上
  • 此時第一個流 就會自動關閉 無法再進行使用了