java8特性-函數(shù)式接口

參考文章
http://lucida.me/blog/java-8-lambdas-insideout-language-features/
http://www.jb51.net/article/48304.htm
JDK1.8包含了很多內(nèi)建的函數(shù)式接口镀裤,在老Java中常用到的比如Comparator或者Runnable接口握牧,這些接口都增加了@FunctionalInterface注解以便能用在lambda上怀浆。

  • Predicate接口
    Predicate 接口只有一個(gè)參數(shù)本橙,返回boolean類型磕谅。該接口包含多種默認(rèn)方法來(lái)將Predicate組合成其他復(fù)雜的邏輯(比如:與狐蜕,或骏掀,非):
Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo");              // true
predicate.negate().test("foo");     // false
Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
  • Comparator
Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);
Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");
comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0
  • Function 接口
    Function 接口有一個(gè)參數(shù)并且返回一個(gè)結(jié)果鸠澈,并附帶了一些可以和其他函數(shù)組合的默認(rèn)方法(compose, andThen):
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
backToString.apply("123");     // "123"
  • Supplier 接口
    Supplier 接口返回一個(gè)任意范型的值乔夯,和Function接口不同的是該接口沒(méi)有任何參數(shù)
Supplier<Person> personSupplier = Person::new;
personSupplier.get();   // new Person
  • Consumer 接口
    Consumer 接口表示執(zhí)行在單個(gè)參數(shù)上的操作。
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));
  • Optional 接口
    Optional 不是函數(shù)是接口款侵,這是個(gè)用來(lái)防止NullPointerException異常的輔助類型末荐,這是下一屆中將要用到的重要概念,現(xiàn)在先簡(jiǎn)單的看看這個(gè)接口能干什么:
    Optional 被定義為一個(gè)簡(jiǎn)單的容器新锈,其值可能是null或者不是null甲脏。在Java 8之前一般某個(gè)函數(shù)應(yīng)該返回非空對(duì)象但是偶爾卻可能返回了null,而在Java 8中妹笆,不推薦你返回null而是返回Optional块请。
Optional<String> optional = Optional.of("bam");
optional.isPresent();           // true
optional.get();                 // "bam"
optional.orElse("fallback");    // "bam"
optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"
  • Stream 接口
    Stream 接口
    java.util.Stream 表示能應(yīng)用在一組元素上一次執(zhí)行的操作序列。Stream 操作分為中間操作或者最終操作兩種拳缠,最終操作返回一特定類型的計(jì)算結(jié)果墩新,而中間操作返回Stream本身,這樣你就可以將多個(gè)操作依次串起來(lái)窟坐。Stream 的創(chuàng)建需要指定一個(gè)數(shù)據(jù)源海渊,比如 java.util.Collection的子類,List或者Set哲鸳, Map不支持臣疑。Stream的操作可以串行執(zhí)行或者并行執(zhí)行
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
  • Filter 過(guò)濾
    過(guò)濾通過(guò)一個(gè)predicate接口來(lái)過(guò)濾并只保留符合條件的元素,該操作屬于中間操作徙菠,所以我們可以在過(guò)濾后的結(jié)果來(lái)應(yīng)用其他Stream操作(比如forEach)讯沈。forEach需要一個(gè)函數(shù)來(lái)對(duì)過(guò)濾后的元素依次執(zhí)行。forEach是一個(gè)最終操作婿奔,所以我們不能在forEach之后來(lái)執(zhí)行其他Stream操作缺狠。
stringCollection
    .stream()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);
// "aaa2", "aaa1"
  • Sort 排序
    排序是一個(gè)中間操作,返回的是排序好后的Stream萍摊。如果你不指定一個(gè)自定義的Comparator則會(huì)使用默認(rèn)排序
stringCollection
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);
// "aaa1", "aaa2"

需要注意的是挤茄,排序只創(chuàng)建了一個(gè)排列好后的Stream,而不會(huì)影響原有的數(shù)據(jù)源记餐,排序之后原數(shù)據(jù)stringCollection是不會(huì)被修改的

  • Map 映射
    中間操作map會(huì)將元素根據(jù)指定的Function接口來(lái)依次將元素轉(zhuǎn)成另外的對(duì)象驮樊,下面的示例展示了將字符串轉(zhuǎn)換為大寫字符串。你也可以通過(guò)map來(lái)講對(duì)象轉(zhuǎn)換成其他類型片酝,map返回的Stream類型是根據(jù)你map傳遞進(jìn)去的函數(shù)的返回值決定的囚衔。
stringCollection
    .stream()
    .map(String::toUpperCase)
    .sorted((a, b) -> b.compareTo(a))
    .forEach(System.out::println);
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
  • Match匹配
boolean anyStartsWithA = 
    stringCollection
        .stream()
        .anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA);      // true
boolean allStartsWithA = 
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA);      // false
boolean noneStartsWithZ = 
    stringCollection
        .stream()
        .noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ);      // true
  • Count 計(jì)數(shù)
    計(jì)數(shù)是一個(gè)最終操作,返回Stream中元素的個(gè)數(shù)雕沿,返回值類型是long练湿。
long startsWithB = 
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();
System.out.println(startsWithB);    // 3
  • Reduce 規(guī)約
    這是一個(gè)最終操作,允許通過(guò)指定的函數(shù)來(lái)講stream中的多個(gè)元素規(guī)約為一個(gè)元素审轮,規(guī)越后的結(jié)果是通過(guò)Optional接口表示的:
Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
  • 并行Streams
    前面提到過(guò)Stream有串行和并行兩種肥哎,串行Stream上的操作是在一個(gè)線程中依次完成辽俗,而并行Stream則是在多個(gè)線程上同時(shí)執(zhí)行。
    下面的例子展示了是如何通過(guò)并行Stream來(lái)提升性能:
    首先我們創(chuàng)建一個(gè)沒(méi)有重復(fù)元素的大表:
int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
    UUID uuid = UUID.randomUUID();
    values.add(uuid.toString());
}

然后我們計(jì)算一下排序這個(gè)Stream要耗時(shí)多久篡诽,
串行排序:

long t0 = System.nanoTime();
long count = values.stream().sorted().count();
System.out.println(count);
long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));

// 串行耗時(shí): 899 ms
并行排序

long t0 = System.nanoTime();
long count = values.parallelStream().sorted().count();
System.out.println(count);
long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("parallel sort took: %d ms", millis));

// 并行排序耗時(shí): 472 ms
上面兩個(gè)代碼幾乎是一樣的崖飘,但是并行版的快了50%之多,唯一需要做的改動(dòng)就是將stream()改為parallelStream()杈女。

  • Map
    前面提到過(guò)朱浴,Map類型不支持stream,不過(guò)Map提供了一些新的有用的方法來(lái)處理一些日常任務(wù)达椰。
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
    map.putIfAbsent(i, "val" + i);
}
map.forEach((id, val) -> System.out.println(val));

以上代碼很容易理解翰蠢, putIfAbsent 不需要我們做額外的存在性檢查,而forEach則接收一個(gè)Consumer接口來(lái)對(duì)map里的每一個(gè)鍵值對(duì)進(jìn)行操作啰劲。
下面的例子展示了map上的其他有用的函數(shù)

map.computeIfPresent(3, (num, val) -> val + num);
map.get(3);             // val33
map.computeIfPresent(9, (num, val) -> null);
map.containsKey(9);     // false
map.computeIfAbsent(23, num -> "val" + num);
map.containsKey(23);    // true
map.computeIfAbsent(3, num -> "bam");
map.get(3);             // val33

接下來(lái)展示如何在Map里刪除一個(gè)鍵值全都匹配的項(xiàng)

map.remove(3, "val3");
map.get(3);             // val33
map.remove(3, "val33");
map.get(3);             // null

另外一個(gè)有用的方法:
map.getOrDefault(42, "not found"); // not found
對(duì)Map的元素做合并也變得很容易了:
Merge做的事情是如果鍵名不存在則插入梁沧,否則則對(duì)原鍵對(duì)應(yīng)的值做合并操作并重新插入到map中。

map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9);             // val9
map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9);             // val9concat
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蝇裤,一起剝皮案震驚了整個(gè)濱河市廷支,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猖辫,老刑警劉巖酥泞,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異啃憎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)似炎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門辛萍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人羡藐,你說(shuō)我怎么就攤上這事贩毕。” “怎么了仆嗦?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵辉阶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瘩扼,道長(zhǎng)谆甜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任集绰,我火速辦了婚禮规辱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘栽燕。我一直安慰自己罕袋,他們只是感情好改淑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浴讯,像睡著了一般朵夏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榆纽,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天仰猖,我揣著相機(jī)與錄音,去河邊找鬼掠河。 笑死亮元,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唠摹。 我是一名探鬼主播爆捞,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勾拉!你這毒婦竟也來(lái)了煮甥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤藕赞,失蹤者是張志新(化名)和其女友劉穎成肘,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斧蜕,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡双霍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了批销。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洒闸。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖均芽,靈堂內(nèi)的尸體忽然破棺而出丘逸,到底是詐尸還是另有隱情,我是刑警寧澤掀宋,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布深纲,位于F島的核電站,受9級(jí)特大地震影響劲妙,放射性物質(zhì)發(fā)生泄漏湃鹊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一是趴、第九天 我趴在偏房一處隱蔽的房頂上張望涛舍。 院中可真熱鬧,春花似錦唆途、人聲如沸富雅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)没佑。三九已至毕贼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛤奢,已是汗流浹背鬼癣。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啤贩,地道東北人待秃。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像痹屹,于是被迫代替她去往敵國(guó)和親章郁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容