Java8新特性 - Lambda表達式

一. Java8新特性簡介html

1,速度更快java

2,代碼更少(增長了新的語法Lambda表達式)數組

3,強大的Stream APIapp

4,便於並行dom

5,最大化減小空指針異常Optionalide

 

二. Lambda表達式函數

1. 爲何使用Lambda表達式ui

 Lambda 是一個匿名函數,咱們能夠把 Lambda表達式理解爲是一段能夠傳遞的代碼(將代碼像數據同樣進行傳遞)。能夠寫出更簡潔、更靈活的代碼。做爲一種更緊湊的代碼風格,使Java的語言表達能力獲得了提高。 spa

 

2. Lambda表達式的關鍵:從匿名類到 Lambda 的轉換.net

示例:

Runnable runnable = new Runnable() {
	@Override
	public void run() {
		System.out.println("hello");
	}
};
runnable.run();

Runnable runnable2 = () -> System.out.println("hello2");
runnable2.run();

 

3. Lambda表達式語法

Lambda表達式在Java 語言中引入了一個新的語法元

素和操做符。這個操做符爲 「->」 , 該操做符被稱 

爲 Lambda 操做符或剪頭操做符。它將 Lambda 分爲 

兩個部分:

左側: 指定了 Lambda 表達式須要的全部參數

右側: 指定了 Lambda 體,即 Lambda 表達式要執行

的功能。

(1)語法格式一:無參,無返回值,Lambda 體只需一條語句

  示例:

Runnable r1 = () -> System.out.println("Hello Lambda!");

(2)語法格式二:Lambda 須要一個參數 

  示例:

Consumer<String> con = (x) -> System.out.println(x);

(3)語法格式三:Lambda 只須要一個參數時,參數的小括號能夠省略 

  示例:

Consumer<String> con = x -> System.out.println(x);

(4)語法格式四:Lambda 須要兩個參數,而且有返回值 

  示例:

Comparator<Integer> com = (x, y) -> {
	System.out.println("函數式接口");
	return Integer.compare(x, y);
};

(5)語法格式五:當 Lambda 體只有一條語句時,return 與大括號能夠省略 

  示例:

Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

(6)Lambda 表達式的參數列表的數據類型能夠省略不寫,由於JVM編譯器經過上下文推斷出,數據類型,即「類型推斷」

  示例:

Comparator<Integer> com = (Integer x,Integer y) -> {//Integer 類型能夠省略
	System.out.println("函數式接口");
	return Integer.compare(x, y);
};

省略參數類型:

Comparator<Integer> com = (x,y) -> {
	System.out.println("函數式接口");
	return Integer.compare(x, y);
};

類型推斷:Lambda 表達式中的參數類型都是由編譯器推斷 得出的。 Lambda 表達式中無需指定類型,程序依然可 以編譯,這是由於 javac 根據程序的上下文,在後臺 推斷出了參數的類型。 Lambda 表達式的類型依賴於上 下文環境,是由編譯器推斷出來的。這就是所謂的 「類型推斷」

 

三. 函數式接口

1. 什麼是函數式接口

(1)只包含一個抽象方法的接口,稱爲函數式接口。

(2)你能夠經過 Lambda 表達式來建立該接口的對象。(若 Lambda 表達式拋出一個受檢異常,那麼該異常須要在目標接口的抽象方 法上進行聲明)。 

(3)咱們能夠在任意函數式接口上使用 @FunctionalInterface 註解, 這樣作能夠檢查它是不是一個函數式接口,同時 javadoc 也會包 含一條聲明,說明這個接口是一個函數式接口。

 

2. 自定義函數接口

@FunctionalInterface
public interface TestMyFunction {
	public double getValue();
}

函數式接口中使用泛型:

@FunctionalInterface
public interface TestMyFunction<T> {
	public T getValue(T t);
}

 

3. 做爲參數傳遞的Lambda表達式

public String toUpperString(TestMyFunction<String> mf,String str) {
	return mf.getValue(str);
}

做爲參數傳遞的lambda表達式:

String newStr = toUpperString((str) -> str.toUpperCase(),"abc");
System.out.println(newStr);

做爲參數傳遞 Lambda 表達式:爲了將 Lambda(TestMyFunction<String> mf) 表達式做爲參數傳遞,接收Lambda 表達式的參數類型必須是與該 Lambda 表達式兼容的函數式接口
的類型。 

4,Java 內置四大核心函數式接口 

(1)Consumer<T> : 消費型接口

void accept(T t);

示例:

//Consumer<T> 消費型接口 :
@Test
public void test1() {
	happy(10000, (m) -> System.out.println("大家剛哥喜歡大寶劍,每次消費:" + m + "元"));
}

public void happy(double money, Consumer<Double> con) {
	con.accept(money);
}

 

(2)Supplier<T> : 供給型接口  T get(); 

示例:

//Supplier<T> 供給型接口 :
@Test
public void test2() {
	List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
	for (Integer num : numList) {
		System.out.println(num);
	}
}

//需求:產生指定個數的整數,並放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
	List<Integer> list = new ArrayList<>();
	for (int i = 0; i < num; i++) {
		Integer n = sup.get();
		list.add(n);
	}
	return list;
}


(3),Function<T, R> : 函數型接口   R apply(T t);

示例:

@Test
public void test3() {
	String newStr = strHandler("\t\t\t 我大尚硅谷威武 ", (str) -> str.trim());
	System.out.println(newStr);
	String subStr = strHandler("我大尚硅谷威武", (str) -> str.substring(2, 5));
	System.out.println(subStr);
}

// 需求:用於處理字符串
public String strHandler(String str, Function<String, String> fun) {
	return fun.apply(str);
}


(4),Predicate<T> : 斷言型接口  boolean test(T t);

示例:

//Predicate<T> 斷言型接口:
@Test
public void test4() {
	List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
	List<String> strList = filterStr(list, (s) -> s.length() > 3);
	for (String str : strList) {
		System.out.println(str);
	}
}

// 需求:將知足條件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre) {
	List<String> strList = new ArrayList<>();
	for (String str : list) {
		if (pre.test(str)) {
			strList.add(str);
		}
	}
	return strList;
}


5,其它接口

6,方法引用和構造器引用

方法引用:

當要傳遞給Lambda體的操做,已經有實現的方法了,可使用方法引用!

(實現抽象方法的參數列表,必須與方法引用方法的參數列表保持一致! )

方法引用:使用操做符 「::」 將方法名和對象或類的名字分隔開來。

以下三種主要使用狀況:

(1)對象::實例方法

例如:

@Test
public void test1() {
	PrintStream ps = System.out;
	Consumer<String> con = (str) -> ps.println(str);
	con.accept("Hello World!");

	System.out.println("--------------------------------");

	Consumer<String> con2 = ps::println;
	con2.accept("Hello Java8!");

	Consumer<String> con3 = System.out::println;
}

@Test
public void test2() {
	Employee emp = new Employee(101, "張三", 18, 9999.99);

	Supplier<String> sup = () -> emp.getName();
	System.out.println(sup.get());

	System.out.println("----------------------------------");

	Supplier<String> sup2 = emp::getName;
	System.out.println(sup2.get());
}


(2)類::靜態方法

例如:

@Test
public void test() {
	BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
	System.out.println(fun.apply(1.5, 22.2));

	System.out.println("--------------------------------------------------");
	BiFunction<Double, Double, Double> fun2 = Math::max;
	System.out.println(fun2.apply(1.2, 1.5));
}

@Test
public void test4() {
	Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

	System.out.println("-------------------------------------");
	Comparator<Integer> com2 = Integer::compare;
}


(3)類::實例方法
例如:

@Test
public void test5() {
	BiPredicate<String, String> bp = (x, y) -> x.equals(y);
	System.out.println(bp.test("abcde", "abcde"));

	System.out.println("-----------------------------------------");
	BiPredicate<String, String> bp2 = String::equals;
	System.out.println(bp2.test("abc", "abc"));

	System.out.println("-----------------------------------------");
	Function<Employee, String> fun = (e) -> e.show();
	System.out.println(fun.apply(new Employee()));

	System.out.println("-----------------------------------------");
	Function<Employee, String> fun2 = Employee::show;
	System.out.println(fun2.apply(new Employee()));
}

 

注意:

 * ①方法引用所引用的方法的參數列表與返回值類型,須要與函數式接口中抽象方法的參數列表和返回值類型保持一致!

 * ②若Lambda 的參數列表的第一個參數,是實例方法的調用者,第二個參數(或無參)是實例方法的參數時,格式: ClassName::MethodName

 

構造器引用:構造器的參數列表,須要與函數式接口中參數列表保持一致!

格式: ClassName::new

與函數式接口相結合,自動與函數式接口中方法兼容。

能夠把構造器引用賦值給定義的方法,與構造器參數

列表要與接口中抽象方法的參數列表一致!

Function<Integer,MyClass> fun = (n) -> new MyClass(n);

//等同於
Function<Integer,MyClass> fun2 = MyClass::new;

數組引用:

 格式: type[] ::new

Function<Integer,Integer[]> fun = (n) -> new Integer[n];

//等同於
Function<Integer,Integer[]> fun2 = Integer[]::new;

 

Lambda其餘博文介紹:

https://www.cnblogs.com/zhenghengbin/p/9418961.html

https://www.cnblogs.com/songyz/p/6180278.html

https://my.oschina.net/chenxiaobian/blog/704421

相關文章
相關標籤/搜索