JAVA基础---函数式接口、Stream流
函數(shù)式編程
Stream流
一、函數(shù)式編程:
1、1.概念
函數(shù)式接?在Java中是指:有且僅有?個抽象?法的接?。
函數(shù)式接?,即適?于函數(shù)式編程場景的接?。?Java中的函數(shù)式編程體現(xiàn)就是Lambda,所以函數(shù)式接? 就是可以適?于Lambda使?的接?。只有確保接?中有且僅有?個抽象?法,Java中的Lambda才能順利 地進?推導(dǎo)。
1、2.格式
只要確保接?中有且僅有?個抽象?法即可:
修飾符 interface 接?名稱 {public abstract 返回值類型 ?法名稱(可選參數(shù)信息);// 其他?抽象?法內(nèi)容 }由于接?當(dāng)中抽象?法的 public abstract 是可以省略的,所以定義?個函數(shù)式接?很簡:
public interface MyFunctionalInterface {void myMethod(); }1、3.自定義函數(shù)式接口
對于剛剛定義好的 MyFunctionalInterface 函數(shù)式接?,典型使?場景就是作為?法的參數(shù):
public class Demo1{Private static void do(MyFunctionalInterface inter){inter.myMethod();}public static void main(String[] args){do (() -> System.out.println("----"))} }2、常用函數(shù)接口
2、1.Supplier
java.util.function.Supplier 接?僅包含?個?參的?法: T get() 。?來獲取?個泛型參數(shù) 指定類型的對象數(shù)據(jù)。由于這是?個函數(shù)式接?,這也就意味著對應(yīng)的Lambda表達式需要“對外提供”? 個符合泛型類型的對象數(shù)據(jù)。
實例:
import java.util.function.Supplier; public class Demo1{private static String getString(Supplier<String> function){return function.get();}public static void main(String[] args){String A = "aa";String B = "bb";System.out.println(getString(() -> A + B));} }2.2.Consumer
java.util.function.Consumer 接?則正好與Supplier接?相反,它不是?產(chǎn)?個數(shù)據(jù),?是消費 ?個數(shù)據(jù),其數(shù)據(jù)類型由泛型決定。
抽象方法:accept
Consumer 接?中包含抽象?法 void accept(T t) ,意為消費?個指定泛型的數(shù)據(jù)。基本使?如:
import java.util.function.Consumer; public class Demo1{private static void consumeString(Consumer<String> function){ function.accept("aa");}public static void main(String[] args){consumeString(s -> System.out.println(s));} }默認方法:andThen
如果?個?法的參數(shù)和返回值全都是 Consumer 類型,那么就可以實現(xiàn)效果:消費數(shù)據(jù)的時候,?先做? 個操作,然后再做?個操作,實現(xiàn)組合。?這個?法就是 Consumer 接?中的default?法 andThen 。 要想實現(xiàn)組合,需要兩個或多個Lambda表達式即可 。
2、3.Predicate
有時候我們需要對某種類型的數(shù)據(jù)進?判斷,從?得到?個boolean值結(jié)果。這時可以 使 java.util.function.Predicate 接?。
抽象方法:test
有時候我們需要對某種類型的數(shù)據(jù)進?判斷,從?得到?個boolean值結(jié)果。這時可以 使 java.util.function.Predicate 接?。
import java.util.function.Predicate; public class Demo15PredicateTest {private static void method(Predicate<String> predicate) {boolean veryLong = predicate.test("HelloWorld");System.out.println("字符串很?嗎:" + veryLong);}public static void main(String[] args) {method(s -> s.length() > 5);} } 默認方法:2.3.2、and:既然是條件判斷,就會存在與、或、?三種常?的邏輯關(guān)系。其中將兩個 Predicate 條件使?“與”邏輯連 接起來實現(xiàn)“并且”的效果時,可以使?default?法 and 。其JDK源碼為 ```java default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t); }2.3.3、or:
與 and 的“與”類似,默認?法 or 實現(xiàn)邏輯關(guān)系中的“或”。JDK源碼為:
default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t); }2.3.4、negate:
“與”、“或”已經(jīng)了解了,剩下的“?”(取反)也會簡單。默認?法 negate 的JDK源代碼為:
default Predicate<T> negate() {return (t) -> !test(t); }ps:它是執(zhí)?了test?法之后,對結(jié)果boolean值進?“!”取反?已。?定要在 test ?法 調(diào)?之前調(diào)? negate ?法,正如 and 和 or ?法?樣:
2、4.Function:
java.util.function.Function 接??來根據(jù)?個類型的數(shù)據(jù)得到另?個類型的數(shù)據(jù),前者稱為 前置條件,后者稱為后置條件。
抽象?法:apply
Function 接?中最主要的抽象?法為: R apply(T t) ,根據(jù)類型T的參數(shù)獲取類型R的結(jié)果。 使?的場景例如:將 String 類型轉(zhuǎn)換為 Integer 類型。
import java.util.function.Function; public class Demo11FunctionApply {private static void method(Function<String, Integer> function) {int num = function.apply("10");System.out.println(num + 20);}public static void main(String[] args) {method(s -> Integer.parseInt(s));} }默認方法: andThen
Function 接?中有?個默認的 andThen ?法,?來進?組合操作。JDK源代碼如:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t)); }ps: 該?法同樣?于“先做什么,再做什么”的場景,和 Consumer 中的 andThen 差不多
二、Stream流
1.1獲取流的方法
java.util.stream.Stream 是Java 8新加?的最常?的流接?。(這并不是?個函數(shù)式接?。) 獲取?個流?常簡單,有以下?種常?的?式:
所有的 Collection 集合都可以通過 stream 默認?法獲取流;
Stream 接?的靜態(tài)?法 of 可以獲取數(shù)組對應(yīng)的流。
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Stream;public class Demo1 {public static void main(String[] args) {//獲得Stream對象//List獲得stream對象List <String> list = List.of("鄙人","張麻子","黃四郎");//快速生成集合,創(chuàng)建之后不可變Stream<String> stream = list.stream();//set獲得stream對象Set<String > set = Set.of("鄙人","張麻子","黃四郎");Stream<String> stream1 = set.stream();//Map獲得stream對象Map<String ,Integer>map = Map.of("鄙人",1,"張麻子",2,"黃四郎",3);Stream<String> stream2 = map.keySet().stream();Stream<Integer> stream3 = map.values().stream();Stream<Map.Entry<String, Integer>> stream4 = map.entrySet().stream();//數(shù)組獲得stream對象String [] strArr = {"鄙人","張麻子","黃四郎"};Stream<String> stream6 = Arrays.stream(strArr);Stream<Integer> stream5 = Stream.of(1,2,3,4,5);} }1、2.常用方法:
1.2.1:逐一處理:forEach
雖然?法名字叫 forEach ,但是與for循環(huán)中的“for-each”昵稱不同。
void forEach(Consumer<? super T> action);該?法接收?個 Consumer 接?函數(shù),會將每?個流元素交給該函數(shù)進?處理。
實例:
import java.util.stream.Stream; public class Demo12StreamForEach {public static void main(String[] args) {Stream<String> stream = Stream.of("鄙人", "張麻子", "黃老爺");stream.forEach(name-> System.out.println(name));} }1.2.2:過濾:filter
可以通過 filter ?法將?個流轉(zhuǎn)換成另?個?集流。?法簽名:
Stream<T> filter(Predicate<? super T> predicate);該接?接收?個 Predicate 函數(shù)式接?參數(shù)(可以是?個Lambda或?法引?)作為篩選條件。
該?法將會產(chǎn)??個boolean值結(jié)果,代表指定的條件是否滿?。如果結(jié)果為true,那么Stream流的 filter ?法將會留?元素;如果結(jié)果為false,那么 filter ?法將會舍棄元素。
實例: 通過Lambda表達式來指定了篩選的條件:必須姓張。
import java.util.stream.Stream; public class Demo07StreamFilter {public static void main(String[] args) {Stream<String> original = Stream.of("張麻子", "黃四郎", "九筒");Stream<String> result = original.filter(s -> s.startsWith("張"));} }1.2.3:映射:map
如果需要將流中的元素映射到另?個流中,可以使? map ?法。?法簽名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);該接?需要?個 Function 函數(shù)式接?參數(shù),可以將當(dāng)前流中的T類型數(shù)據(jù)轉(zhuǎn)換為另?種R類型的流。
實例: map ?法的參數(shù)通過?法引?,將字符串類型轉(zhuǎn)換成為了int類型(并?動裝箱為 Integer類對象)。
import java.util.stream.Stream; public class Demo08StreamMap {public static void main(String[] args) {Stream<String> original = Stream.of("10", "12", "18");Stream<Integer> result = original.map(str->Integer.parseInt(str));} }1.2.4:統(tǒng)計個數(shù):count
正如舊集合 Collection 當(dāng)中的 size ?法?樣,流提供 count ?法來數(shù)?數(shù)其中的元素個數(shù):
long count();該?法返回?個long值代表元素個數(shù)(不再像舊集合那樣是int值)。
import java.util.stream.Stream; public class Demo09StreamCount {public static void main(String[] args) {Stream<String> original = Stream.of("鄙人","張麻子","黃四郎");Stream<String> result = original.filter(s -> s.startsWith("張"));System.out.println(result.count()); // 2} }1.2.5: 取?前?個:limit
limit ?法可以對流進?截取,只取?前n個。?法簽名:
Stream<T> limit(long maxSize);參數(shù)是?個long型,如果集合當(dāng)前?度?于參數(shù)則進?截取;否則不進?操作。基本使?:
import java.util.stream.Stream; public class Demo10StreamLimit {public static void main(String[] args) {Stream<String> original = Stream.of("鄙人","張麻子","黃四郎");Stream<String> result = original.limit(2);System.out.println(result.count()); // 2} }1.2.6: 跳過前?個:skip
如果希望跳過前?個元素,可以使? skip ?法獲取?個截取之后的新流:
Stream<T> skip(long n);如果流的當(dāng)前?度?于n,則跳過前n個;否則將會得到?個?度為0的空流。基本使?:
import java.util.stream.Stream; public class Demo11StreamSkip {public static void main(String[] args) {Stream<String> original = Stream.of("鄙人","張麻子","黃四郎");Stream<String> result = original.skip(2);System.out.println(result.count()); // 1} }1.2.7: 組合:concat
如果有兩個流,希望合并成為?個流,那么可以使? Stream 接?的靜態(tài)?法 concat :
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) 實例: import java.util.stream.Stream; public class Demo12StreamConcat {public static void main(String[] args) {Stream<String> streamA = Stream.of("張麻子");Stream<String> streamB = Stream.of("張起靈");Stream<String> result = Stream.concat(streamA, streamB);} }1、3 小結(jié)練習(xí)
題? :現(xiàn)在有兩個 ArrayList 集合存儲隊伍當(dāng)中的多個成員姓名,要求使?傳統(tǒng)的for循環(huán)(或增強for循環(huán))依 次進?以下若?操作步驟:
第?個隊伍只要名字為3個字的成員姓名;存儲到?個新集合中。
第?個隊伍篩選之后只要前3個?;存儲到?個新集合中。
第?個隊伍只要姓張的成員姓名;存儲到?個新集合中。
第?個隊伍篩選之后不要前2個?;存儲到?個新集合中。
將兩個隊伍合并為?個隊伍;存儲到?個新集合中。
根據(jù)姓名創(chuàng)建 Person 對象;存儲到?個新集合中。
打印整個隊伍的Person對象信息。
package Stream;import java.util.ArrayList; import java.util.stream.Stream;public class Demo4 {public static void main(String[] args) {//第??隊伍ArrayList<String> one = new ArrayList<>();one.add("迪麗熱巴");one.add("宋遠橋");one.add("蘇星河");one.add("?破天");one.add("?中?");one.add("??");one.add("莊?");one.add("洪七公");//第??隊伍ArrayList<String> two = new ArrayList<>();two.add("古?娜扎");two.add("張?忌");two.add("趙麗穎");two.add("張三豐");two.add("尼古拉斯趙四");two.add("張?zhí)鞇?#34;);two.add("張?狗");Stream<String> s1 = one.stream().filter(t -> t.length() == 3).limit(3);Stream<String> s2 = two.stream().filter(t -> t.startsWith("張")).skip(2);Stream<String> stream = Stream.concat(s1, s2);stream.map(name -> new Person(name)).forEach(p -> System.out.println(p ));} }總結(jié)
以上是生活随笔為你收集整理的JAVA基础---函数式接口、Stream流的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图片轮换-jQuery
- 下一篇: 整型变量和整型常量