国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

函數(shù)式編程

2019-11-14 11:11:05
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

為什么要用函數(shù)式編程。看例子:

final List<BigDecimal> PRices = Arrays.asList(    new BigDecimal("10"), new BigDecimal("30"), new BigDecimal("17"),    new BigDecimal("20"), new BigDecimal("15"), new BigDecimal("18"),    new BigDecimal("45"), new BigDecimal("12"));BigDecimal totalOfDiscountedPrices = BigDecimal.ZERO;for(BigDecimal price : prices) {    if(price.compareTo(BigDecimal.valueOf(20)) > 0)        totalOfDiscountedPrices = totalOfDiscountedPrices.add(price.multiply(BigDecimal.valueOf(0.9)));}System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);

更優(yōu)雅的方式,是使用聲明式的代碼:

final BigDecimal totalOfDiscountedPrices =     prices.stream()          .filter(price -> price.compareTo(BigDecimal.valueOf(20)) > 0)          .map(price -> price.multiply(BigDecimal.valueOf(0.9)))          .reduce(BigDecimal.ZERO, BigDecimal::add);System.out.println("Total of discounted prices: " + totalOfDiscountedPrices);

使用函數(shù)式代碼的好處:

減少了可變量(Immutable Variable)的聲明能夠更好的利用并行(Parallelism)代碼更加簡(jiǎn)潔和可讀

函數(shù)式接口

函數(shù)式接口就是僅聲明了一個(gè)方法的接口,比如我們熟悉的Runnable,Callable,Comparable等都可以作為函數(shù)式接口。當(dāng)然,在java 8中,新添加了一類(lèi)函數(shù)式接口,如Function,Predicate,Consumer,Supplier等。

@FunctionalInterfacepublic static interface IntHandler{    void handle(int i);}

在函數(shù)式接口中,可以聲明0個(gè)或者多個(gè)default方法,這些方法在接口內(nèi)就已經(jīng)被實(shí)現(xiàn)了。因此,接口的default方法也是Java 8中引入的一個(gè)新概念。

default method 默認(rèn)方法,又稱(chēng)作虛擬擴(kuò)展方法或保衛(wèi)者方法,例子:

import java.util.Objects;import java.util.function.Consumer;public interface Iterable<T> {    default void forEach(Consumer<? super T> action) {        Objects.requireNonNull(action);        for (T t : this) {            action.accept(t);        }    }}

為什么需要default method?

即使你的API已經(jīng)發(fā)布出去了,你依然可以為接口添加新方法并且無(wú)需考慮向后兼容問(wèn)題。java8 對(duì)Lambda的支持必然會(huì)影響JDK API的接口,如果直接在接口中添加方法,就會(huì)導(dǎo)致所有實(shí)現(xiàn)該接口的類(lèi)或者接口無(wú)法通過(guò)編譯。

函數(shù)式接口使用 @FunctionalInterface注解進(jìn)行標(biāo)注。雖然這個(gè)注解的使用不是強(qiáng)制性的,但是使用它的好處是讓此接口的目的更加明確,同時(shí)編譯器也會(huì)對(duì)代碼進(jìn)行檢查,來(lái)確保被該注解標(biāo)注的接口的使用沒(méi)有語(yǔ)法錯(cuò)誤。

lambda表達(dá)式

lambda表達(dá)式即匿名函數(shù),它是一段沒(méi)有函數(shù)名的函數(shù)體,可以作為參數(shù)直接傳遞給相關(guān)調(diào)用者。

Lambda 表達(dá)式通常使用 (argument) -> (body) 語(yǔ)法書(shū)寫(xiě),例如:

(arg1, arg2...) -> { body }(type1 arg1, type2 arg2...) -> { body }

舉例來(lái)說(shuō):

(int a, int b) -> {  return a + b; }() -> System.out.println("Hello World");(String s) -> { System.out.println(s); }() -> 42() -> { return 3.1415 };

Lambda 表達(dá)式的結(jié)構(gòu)

一個(gè) Lambda 表達(dá)式可以有零個(gè)或多個(gè)參數(shù)參數(shù)的類(lèi)型既可以明確聲明,也可以根據(jù)上下文來(lái)推斷。例如:(int a)與(a)效果相同所有參數(shù)需包含在圓括號(hào)內(nèi),參數(shù)之間用逗號(hào)相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)空?qǐng)A括號(hào)代表參數(shù)集為空。例如:() -> 42當(dāng)只有一個(gè)參數(shù),且其類(lèi)型可推導(dǎo)時(shí),圓括號(hào)()可省略。例如:a -> return a*aLambda 表達(dá)式的主體可包含零條或多條語(yǔ)句如果 Lambda 表達(dá)式的主體只有一條語(yǔ)句,花括號(hào){}可省略。匿名函數(shù)的返回類(lèi)型與該主體表達(dá)式一致如果 Lambda 表達(dá)式的主體包含一條以上語(yǔ)句,則表達(dá)式必須包含在花括號(hào){}中(形成代碼塊)。匿名函數(shù)的返回類(lèi)型與代碼塊的返回類(lèi)型一致,若沒(méi)有返回則為空

每個(gè) Lambda 表達(dá)式都能隱式地賦值給函數(shù)式接口,例如,我們可以通過(guò) Lambda 表達(dá)式創(chuàng)建 Runnable 接口的引用。

Runnable r = () -> System.out.println("hello world");

方法引用

方法引用是Java 8中提出的用來(lái)簡(jiǎn)化lambda表達(dá)式的一種手段。它通過(guò)類(lèi)名和方法名來(lái)定位到一個(gè)靜態(tài)方法或者實(shí)例方法。 方法引用在Java 8中的使用非常靈活。總的來(lái)說(shuō),可以分為以下幾種:

靜態(tài)方法引用:ClassName::methodName

List<Integer> ints = Arrays.asList(1, 2, 3);ints.sort(Integer::compare);

實(shí)例上的實(shí)例方法引用 instanceReference::methodName,方法引用使用”::”定義,”::”的前半部分表示類(lèi)名或者實(shí)例名,后半部分表示方法名稱(chēng)。如果是構(gòu)造函數(shù),則使用new表示。

Words.forEach(System.out::println);words.stream().map(word -> word.length()); // lambdawords.stream().map(String::length); // method reference// lambdawords.stream().map(word -> {    return new StringBuilder(word);});// constructor referencewords.stream().map(StringBuilder::new);

Lambda 表達(dá)式舉例

1.線(xiàn)程初始化

//舊方法:new Thread(new Runnable() {@Overridepublic void run() {    System.out.println("Hello from thread");}}).start();//新方法:new Thread(() -> System.out.println("Hello from thread")).start();

2.打印數(shù)組所有元素,在下面的例子中,我們先是用常用的箭頭語(yǔ)法創(chuàng)建 Lambda 表達(dá)式,之后,使用 Java 8 全新的雙冒號(hào)(::)操作符將一個(gè)常規(guī)方法轉(zhuǎn)化為 Lambda 表達(dá)式:

//Old way:List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);for(Integer n: list) {   System.out.println(n);}//New way:List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);list.forEach(n -> System.out.println(n));//or we can use :: double colon Operator in Java 8list.forEach(System.out::println);

3.斷言函數(shù)式接口使用

import java.util.Arrays;import java.util.List;import java.util.function.Predicate;public class Test {    public static void main(String[] args) {        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);        System.out.println("Print all numbers:");        evaluate(list, n -> true);        System.out.println("Print no numbers:");        evaluate(list, n -> false);        System.out.println("Print even numbers:");        evaluate(list, n -> n % 2 == 0);        System.out.println("Print odd  numbers:");        evaluate(list, n -> n % 2 == 1);        System.out.println("Print numbers greater than 5:");        evaluate(list, n -> n > 5);    }    public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {        for (Integer n : list) {            if (predicate.test(n))                System.out.print(n + " ");        }    }}

Lambda 表達(dá)式與匿名類(lèi)的區(qū)別

使用匿名類(lèi)與 Lambda 表達(dá)式的一大區(qū)別在于關(guān)鍵詞的使用。對(duì)于匿名類(lèi),關(guān)鍵詞 this 解讀為匿名類(lèi),而對(duì)于 Lambda 表達(dá)式,關(guān)鍵詞 this 解讀為寫(xiě)就 Lambda 的外部類(lèi)。

Lambda 表達(dá)式與匿名類(lèi)的另一不同在于兩者的編譯方法。Java 編譯器編譯 Lambda 表達(dá)式并將他們轉(zhuǎn)化為類(lèi)里面的私有函數(shù),它使用 Java 7 中新加的 invokedynamic 指令動(dòng)態(tài)綁定該方法

接口與抽象類(lèi)

雖然 Java 8 的接口的默認(rèn)方法就像抽象類(lèi),能提供方法的實(shí)現(xiàn),但是他們倆仍然是 不可相互代替的:

接口可以被類(lèi)多實(shí)現(xiàn)(被其他接口多繼承),抽象類(lèi)只能被單繼承。接口中沒(méi)有 this 指針,沒(méi)有構(gòu)造函數(shù),不能擁有實(shí)例字段(實(shí)例變量)或?qū)嵗椒ǎ瑹o(wú)法保存 狀態(tài)(state),抽象方法中可以。抽象類(lèi)不能在 java 8 的 lambda 表達(dá)式中使用。從設(shè)計(jì)理念上,接口反映的是 “l(fā)ike-a” 關(guān)系,抽象類(lèi)反映的是 “is-a” 關(guān)系。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 凌源市| 平顶山市| 溆浦县| 泰州市| 丹巴县| 灯塔市| 礼泉县| 克拉玛依市| 铁岭县| 邛崃市| 沈阳市| 桑日县| 泸州市| 泾源县| 吴江市| 永年县| 通化县| 崇明县| 宜城市| 来宾市| 武宣县| 浦江县| 镇沅| 兴业县| 莱阳市| 武义县| 乌恰县| 荔浦县| 仁寿县| 疏勒县| 斗六市| 寿阳县| 安化县| 大姚县| 阿拉善盟| 荆门市| 齐齐哈尔市| 葵青区| 嵊州市| 荣成市| 金沙县|