日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习笔记之-java8的新特性-函数式接口,lambda表达式,方法引用,Stream API,Optional类

發(fā)布時間:2024/4/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习笔记之-java8的新特性-函数式接口,lambda表达式,方法引用,Stream API,Optional类 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.Lambda表達式

用匿名內(nèi)部類的方法去創(chuàng)建多線程1.new Thread2.參數(shù)傳遞new Runnable3.重寫run方法4.在run方法中去設(shè)置線程任務(wù)5.調(diào)用start問題:我們最終目標是:設(shè)置線程任務(wù)-->實現(xiàn)run方法所以,我們從函數(shù)式編程思想角度出發(fā),我們更注重干什么,而不注重怎么干說白了,我們注重的就是方法體,從函數(shù)式編程思想角度出發(fā),其他的,我們其實無需關(guān)注

lambda表達式的定義格式
1.格式:
(數(shù)據(jù)類型 變量名) -> {方法體}
2.格式詳解
(數(shù)據(jù)類型 變量名) : 重寫方法的參數(shù)
-> : 代表的是將參數(shù)傳遞到方法體中
{方法體} : 重寫方法的方法體

為什么使用Lambda表達式?
Lambda是一個匿名函數(shù),我們可以把Lambda表達式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進行傳遞)。可以與出史間白、史靈活的代碼。作為一種更緊湊的代碼風格,使Java的語言表達能力得到了提升。

一、Lambda表達式的基礎(chǔ)語法:

Java8中引入了一個新的操作符“->”該操作符稱為箭頭操作符或Lambda操作符
箭頭操作符將Lambda表達式拆分成兩部分:
左側(cè):Lambda表達式的參數(shù)列表
右側(cè):Lambda表達式中所需執(zhí)行的功能,即Lambda體

語法格式一:無參數(shù),無返回值

()->System.out.print1n("Hello Lambda ! " );

public class TestLambda01 {public static void main(String[] args) {int i = 0;//使用匿名內(nèi)部類new Runnable() {//在jak7以前,匿名內(nèi)部類中引用外部變量,會報錯,但是jdk8不會public void run() {System.out.println("Hello Lambda ! "+i);}}.run();Runnable r = () -> System.out.println("Hello Lambda ! "+i);r.run();} }

語法格式二:有一個參數(shù),并且無返回值

(x) -> System.out.println(x);

public class TestLambda02 {public static void main(String[] args) { /* 語法格式二:有一個參數(shù),并且無返回值 () -> System.out.println(x)~*/Consumer c = (x) -> System.out.println(x);c.accept("小付要快樂呀~~~");} }

語法格式三:若只有一個參數(shù),小括號可以省略不寫

x -> System.out.println(x);

public class TestLambda02 {public static void main(String[] args) {Consumer c = x -> System.out.println(x);c.accept("小付要快樂呀~~~");} }

語法格式四:有兩個以上的參數(shù),有返回值,并且 Lambda 體中有多條語句

(x,y)->{
System.out.print1n(“函數(shù)式接口”);
return Integer.compare(x, y);}

public class TestLambda02 {public static void main(String[] args) {Comparator<Integer> c = (x,y) ->{System.out.println(x);System.out.println(y);return Integer.compare(x,y);};System.out.println(c.compare(1,2));} }

語法格式五:若 Lambda 體中只有一條語句,return和大括號都可以省略不寫

public class TestLambda02 {public static void main(String[] args) {Comparator<Integer> c = (Integer x,Integer y) -> Integer.compare(x,y);System.out.println(c.compare(1,2));} }

語法格式六:Lambdar表達式的參數(shù)列表的數(shù)據(jù)類型可以省略不寫

因為JVW編譯器通過上下文推斷出,數(shù)據(jù)類型,即“類型推斷

public class TestLambda02 {public static void main(String[] args) {Comparator<Integer> c = (x,y) -> Integer.compare(x,y);System.out.println(c.compare(1,2));} }

省略規(guī)則

在Lambda標準格式的基礎(chǔ)上,使用省略寫法的規(guī)則為:

  • 小括號內(nèi)參數(shù)的類型可以省略;
  • 如果小括號內(nèi)有且僅有一個參,則小括號可以省略;
  • 如果大括號內(nèi)有且僅有一個語句,則無論是否有返回值,都可以省略大括號、return關(guān)鍵字及語句分號。
  • lambda表達式的使用前提:

    1.必須有接口參與: 2.接口必須有且僅有一個抽象方法-->函數(shù)式接口 3.接口必須作為方法的參數(shù)使用

    2.函數(shù)式接口

    函數(shù)式接口
    1.必須是接口
    2.接口中必須有且僅有一個抽象方法
    3.可以用注解驗證是不是函數(shù)式接口–>@FunctionalInterface

    Java內(nèi)置四大核心函數(shù)式接口

    Consumer<T> :消費型接口
    void accept(T t);

    public class TestLambda03 {public static void main(String[] args) {//Consumer<T\> :消費型接口happy(100,(m) -> System.out.println("花了:"+m+"元,快樂每一天"));}public static void happy(double money, Consumer<Double> consumer){consumer.accept(money);} }

    supplier<T>∶:供給型接口
    T get();

    public class TestLambda03 {public static void main(String[] args) {//Supplier<T\>∶:供給型接口int money = happy(()-> (int)(Math.random()*100));System.out.println("小付賺了:"+money);}public static int happy(Supplier<Integer> supplier){return supplier.get();} }

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

    public class TestLambda03 {public static void main(String[] args) {//Function<T,R>:函數(shù)型接口//用于處理字符串需求String ha = happy("/t/t/t 小付快樂啊", s -> s.replace("/t", "ha"));System.out.println(ha);}public static String happy(String s,Function<String,String> function){return function.apply(s);} }

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

    public class TestLambda03 {public static void main(String[] args) {//Predicate<T\> :斷言型接口//需求:將滿足條件的字符串放入集合中ArrayList<String> strings = new ArrayList<>();strings.add("123");strings.add("221123");strings.add("2");strings.add("31");strings.add("2");strings.add("4414");List<String> happy = happy(strings, s -> s.length()>3);System.out.println(happy);}public static List<String> happy(List<String> s, Predicate<String> predicate){ArrayList<String> strings = new ArrayList<>();for (String s1 : s) {if (predicate.test(s1)){strings.add(s1);}}return strings;} }

    其他接口

    3.方法引用與構(gòu)造器引用與數(shù)組引用

    方法引用:若 Lambda 體中的內(nèi)容有方法已經(jīng)實現(xiàn)了,我們可以使用"方法引用”
    (可以理解為方法引用是Lambda 表達式的另外一種表現(xiàn)形式)

    方法引用主要有三種語法格式:

    對象::實例方法名

    public class Method01 {public static void main(String[] args) { // Consumer<String> s = s1 -> System.out.println(s1);//對象::實例方法名//注意:需要實現(xiàn)的接口的方法的參數(shù)列表與實際實現(xiàn)的方法的參數(shù)一致Consumer<String> s = System.out::println;s.accept("123");} }

    package com.fs.fang;public class Method01 {public static void main(String[] args) {Student student = new Student();student.setName("小付");student.setAge(26);//對象::實例方法名MethodDemo m = student::methodTest;m.methodMy(16,"帥帥");System.out.println(student.getName()+student.getAge());} }//創(chuàng)建函數(shù)式接口 @FunctionalInterface interface MethodDemo{abstract void methodMy(Integer age,String name); }class Student{private String name;private Integer age;public void methodTest(Integer age,String name){this.age = age;this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;} } public class Method01 {public static void main(String[] args) {Student student = new Student();student.setName("小付");//對象::實例方法名Supplier<String> supplier = student::getName;System.out.println(supplier.get());} }class Student{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;} }

    @Lambda 體中調(diào)用方法的參數(shù)列表與返回值類型,要與函數(shù)式接口中抽象方法的函數(shù)列表和返回值類型保持一致!

    類::靜態(tài)方法名

    public class Method02 {public static void main(String[] args) {//類::靜態(tài)方法名//案列:比較大小 // Comparator<Integer> c = (x,y)-> Integer.compare(x,y);Comparator<Integer> c = Integer::compare;int compare = c.compare(1, 2);System.out.println(compare);} }

    類::實例方法名

    public class Method02 {public static void main(String[] args) {//類::實例方法名//案列:比較2個字符串是否一樣 // BiPredicate<String,String> b = (x,y)->x.equals(y);//第一個參數(shù)是實例方法的調(diào)用者,第二個參數(shù)是這個實例參數(shù),就可以用方法引用BiPredicate<String,String> b = String::equals;System.out.println(b.test("1", "2"));//false} }

    @若Lambda 參數(shù)列表中的第一參數(shù)是實例方法的調(diào)用者,而第二個參數(shù)是實例方法的參數(shù)時,可以使用ClassName :: method

    注意:

    @Lambda 體中調(diào)用方法的參數(shù)列表與返回值類型,要與函數(shù)式接口中抽象方法的函數(shù)列表和返回值類型保持一致!
    @若Lambda 參數(shù)列表中的第一參數(shù)是實例方法的調(diào)用者,而第二個參數(shù)是實例方法的參數(shù)時,可以使用ClassName :: method

    構(gòu)造器引用語法

    格式:
    ClassName: : new

    public class Method02 {public static void main(String[] args) {//類::new // Supplier<Student> s = ()->new Student(); // Student student = s.get();//因為Supplier接口的方法get()是無參的,所以這個Student::new調(diào)用的是無參構(gòu)造Supplier<Student> s = Student::new;Student student = s.get();} }

    構(gòu)造器引用注意:
    需要調(diào)用的構(gòu)造器的參數(shù)列表要與函數(shù)式接口中抽象方法的參數(shù)列表保持一致!

    數(shù)組引用語法

    Type[]::new

    public class Method02 {public static void main(String[] args) {//數(shù)組引用//Type[]::new// Function<Integer,String[]> f = (x) -> new String[x]; // String[] apply = f.apply(10); // System.out.println(apply.length);//10Function<Integer,String[]> f = String[]::new;String[] apply = f.apply(10);System.out.println(apply.length);//10} }

    4.Stream APl

    Stream概念

    Java8中有兩大最為重要的改變。第一個是 Lambda表達式;另外一個則是`StreamAPI(java.util.stream.*)。Stream是Java8中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。使用Stream API對集合數(shù)據(jù)進行操作,就類似于使用SQL執(zhí)行的數(shù)據(jù)庫查詢。也可以使用Stream API 來并行執(zhí)行操作。簡而言之,Stream API提供了一種高效且易于使用的處理數(shù)據(jù)的方式。

    什么是Stream

    流(Stream)到底是什么呢?
    是數(shù)據(jù)渠道,用于操作數(shù)據(jù)源(集合、數(shù)組等)所生成的元素序列。“集合講的是數(shù)據(jù),流講的是計算!”

    注意:

    ①Stream自己不會存儲元素。
    ②Stream不會改變源對象。相反,他們會返回一個持有結(jié)果的新Stream。
    ③Stream操作是延遲執(zhí)行的。這意味著他們會等到需要結(jié)果的時候才執(zhí)行。

    Stream 的操作三個步驟

    創(chuàng)建Stream

    一個數(shù)據(jù)源(如:集合、數(shù)組),獲取一個流

    //創(chuàng)建Stream //一個數(shù)據(jù)源(如:集合、數(shù)組),獲取一個流//1。可以通過Collection系列集合提供的stream()或parallelStream()ArrayList<String> strings = new ArrayList<>();Stream<String> stream = strings.stream();//得到流//2。通過Arrays中的靜態(tài)方法stream()獲取數(shù)組流int[] ints = new int[10];IntStream intStream = Arrays.stream(ints);//3。通過Stream類中的靜態(tài)方法 of()Stream<String> stringStream = Stream.of("a", "b", "c");//4。創(chuàng)建無限流//迭代創(chuàng)建無限流Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);//要前10個(中間操作) 遍歷輸出(終結(jié)操作)iterate.limit(10).forEach(System.out::println);//生成創(chuàng)建無限流 并且遍歷輸出(終結(jié)操作)Stream.generate(()->Math.random()).forEach(System.out::println);

    中間操作

    一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進行處理

    多個中間操作可以連接起來形成一個流水線,除非流水線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何的處理!而在終止操作時一次性全部處理,稱為“惰性求值”。

    中間操作:不會執(zhí)行任何操作
    終止操作:一次性執(zhí)行全部內(nèi)容,即"惰性求值”

    篩選與切片

    篩選與切片
    filter——接收Lambda ,從流中排除某些元素。
    limit——截斷流,使其元素不超過給定數(shù)量。
    skip(n)—跳過元素,返回一個扔掉了前n個元素的流。若流中元素不足n個,則返回一個空流。與limit(n)互補
    distinct—篩選,通過流所生成元素的 hashCode()和equals()去除重復(fù)元素


    代碼演示

    public static void main(String[] args) { //中間操作 // 一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進行處理、 /* 篩選與切片 filter——接收Lambda ,從流中排除某些元素。 limit——截斷流,使其元素不超過給定數(shù)量。 skip(n)—跳過元素,返回一個扔掉了前n個元素的流。若流中元素不足n個,則返回一個空流。與limit(n)互補 distinct()—篩選,通過流所生成元素的 hashCode()和equals()去除重復(fù)元素*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00),new Student("張三", 56, 4444.00),new Student("李四", 23, 5555.00),new Student("王五", 74, 6666.00),new Student("趙六", 12, 7777.00),new Student("田七", 45, 8888.00),new Student("田七", 45, 8888.00));//1.創(chuàng)建流students.stream()//filter——接收Lambda ,從流中排除某些元素。.filter(student -> student.getAge()>35)//limit——截斷流,使其元素不超過給定數(shù)量。.limit(4)//skip(n)—跳過元素,返回一個扔掉了前n個元素的流。若流中元素不足n個,則返回一個空流。與limit(n)互補.skip(1)//distinct()—篩選,通過流所生成元素的 hashCode()和equals()去除重復(fù)元素 // .distinct()由于是對象, hashCode() 值不相等,所以這里去重不來對象屬性相等的對象//forEach 終結(jié)操作,遍歷輸出.forEach(System.out::println);//這里就可以.distinct()去重List<String> strings = Arrays.asList("1","1","4","3","2");//獲取流 只要字符串長度==1的 保留前5個,去除前0個 去重 遍歷輸出strings.stream().filter(s -> s.length()==1).limit(5).skip(0).distinct().forEach(System.out::println);/*控制臺輸出 Student{name='王五', age=74, money=6666.0} Student{name='田七', age=45, money=8888.0} Student{name='田七', age=45, money=8888.0} 1 4 3 2*/} }class Student{private String name;private Integer age;private Double money;public Student() {}public Student(String name, Integer age, Double money) {this.name = name;this.age = age;this.money = money;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", money=" + money +'}';} }

    映射


    map—接收Lambda ,將元素轉(zhuǎn)換成其他形式或提取信息。接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素。
    代碼案例

    /*** 映射* map—接收Lambda ,將元素轉(zhuǎn)換成其他形式或提取信息。接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素。*/ public class Stream02 {public static void main(String[] args) { //中間操作 // 一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進行處理、List<String> strings = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");//將數(shù)組中的字符串轉(zhuǎn)為大寫 并且遍歷輸出strings.stream()//map—接收Lambda ,將元素轉(zhuǎn)換成其他形式或提取信息。接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素。//map 通俗 的意思就是集合中的每個元素,都執(zhí)行一遍這個lambda表達式的函數(shù),案例使用的函數(shù)是 轉(zhuǎn)成大寫,所以每個值都轉(zhuǎn)成了大寫 // .map(s -> s.toUpperCase()).map(String::toUpperCase).forEach(System.out::println);List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00),new Student("張三", 56, 4444.00),new Student("李四", 23, 5555.00),new Student("王五", 74, 6666.00),new Student("趙六", 12, 7777.00),new Student("田七", 45, 8888.00),new Student("田七", 45, 8888.00));//map案例 提取學生的名字并去重students.stream()//方法引用 類::實列方法名//獲取到 集合中的學生的名字 去重,并且遍歷 輸出.map(Student::getName).distinct().forEach(System.out::println);//map案例2 調(diào)用我們自己的方法 返回一個流,Stream<Stream<Integer>> streamStream = students.stream().map(Stream02::getStreamName);//將返回 的流遍歷的每一個流做處理streamStream.forEach(integerStream -> integerStream.filter(integer -> integer>30).forEach(System.out::println));}//返回一個 流public static Stream<Integer> getStreamName(Student student){//下面代碼模擬業(yè)務(wù),很大一坨業(yè)務(wù)List<Integer> strings = new ArrayList<>();strings.add(student.getAge());return strings.stream();} }

    flatMap—接收一個函數(shù)作為參數(shù),將流中的每個值都換成另一個流,然后把所有流連接成一個流

    public class StreamDemo {public static void main(String[] args) { //中間操作 // 一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進行處理、 /* 映射 flatMap—接收一個函數(shù)作為參數(shù),將流中的每個值都換成另一個流,然后把所有流連接成一個流 */List<String> strings = new ArrayList<>();strings.add("aaa");strings.add("bbb");strings.add("ccc");strings.add("ddd");strings.add("eee");//案列,拆分上面集合中的字符串//使用map //{ {a, a, a}, {b,b, b}......}Stream<Stream<Character>> streamStream = strings.stream().map(StreamDemo::filterCharacter);streamStream.forEach(stream->stream.forEach(System.out::println));//使用flatMap //{a, a, a, b, b, b.....}Stream<Character> characterStream = strings.stream().flatMap(StreamDemo::filterCharacter);characterStream.forEach(System.out::println);}//傳遞一個字符串,返回拆分該字符串的list流public static Stream<Character> filterCharacter(String str) {List<Character> list = new ArrayList<>();for (Character ch : str.toCharArray()) {list.add(ch);}return list.stream();} }

    map與flatMap對比

    排序

    public class StreamDemo {public static void main(String[] args) { // 排序 // sorted(——自然排序(Comparable) // sorted (comparator com)——定制排序(comparator)List<String> strings = Arrays.asList( "ccc", "aaa", "bbb", "ddd", "eee");// sorted(——自然排序strings.stream().sorted().forEach(System.out::println);// sorted (comparator com)——定制排序List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00),new Student("張三", 56, 4444.00),new Student("李四", 23, 5555.00),new Student("王五", 74, 6666.00),new Student("趙六", 12, 7777.00),new Student("田七", 45, 8888.00),new Student("田七", 46, 8888.00));//按照年齡降序排序students.stream().sorted((x,y)-> {if(x.getName().equals(y.getName())){return x.getName().compareTo(y.getName());}else{return -x.getAge().compareTo(y.getAge());}}).forEach(System.out::println);}}

    終止操作(終端操作)

    一個終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果
    終端操作會從流的流水線生成結(jié)果。其結(jié)果可以是任何不是流的值,例如: List、Integer,甚至是void 。

    查找與匹配

    allMatch——檢查是否匹配所有元素
    anyMatch——檢查是否至少匹配一個元素
    noneMatch——檢查是否沒有匹配所有元素
    findFirst——返回第一個元素
    findAny—返回當前流中的任意元素
    count——返回流中元素的總個數(shù)max——返回流中最大值
    min——返回流中最小值

    代碼演示

    public class StreamDemo {public static void main(String[] args) {/* 查找與匹配 allMatch——檢查是否匹配所有元素 anyMatch——檢查是否至少匹配一個元素 noneMatch——檢查是否沒有匹配所有元素 findFirst——返回第一個元素 findAny—返回當前流中的任意元素 count——返回流中元素的總個數(shù) max——返回流中最大值 min——返回流中最小值*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//allMatch——檢查是否匹配所有元素//是否是所有的Student都為Status.BUSY這個狀態(tài)boolean b = students.stream().allMatch(student -> student.getStatus().equals(Status.BUSY));System.out.println(b);//false//anyMatch——檢查是否至少匹配一個元素boolean b1 = students.stream().anyMatch(student -> student.getStatus().equals(Status.FREE));System.out.println(b1);//true//noneMatch——檢查是否沒有匹配所有元素//是否沒有age大于90的Studentboolean b2 = students.stream().noneMatch(student -> student.getAge() > 90);System.out.println(b2);//true//findFirst——返回第一個元素//案列獲取錢最低的 先根據(jù)錢排序,在獲取第一個Optional<Student> first1 = students.stream().sorted((x, y) -> Double.compare(x.getMoney(), y.getMoney())).findFirst();Optional<Student> first = students.stream().sorted(Comparator.comparingDouble(Student::getMoney)).findFirst();System.out.println(first.get());//Student{name='小付', age=16, money=1000.0, status=BUSY}System.out.println(first1.get());//Student{name='小付', age=16, money=1000.0, status=BUSY}//獲取錢最多的Optional<Student> first2 = students.stream().sorted((s1, s2) -> -Double.compare(s1.getMoney(), s2.getMoney())).findFirst();System.out.println(first2.get());//Student{name='田七', age=45, money=8888.0, status=BUSY}//findAny—返回當前流中的任意元素Optional<Student> any = students.parallelStream().findAny();System.out.println(any.get());//隨機獲取一個// count——返回流中元素的總個數(shù)System.out.println(students.stream().count());//7// max——返回流中最大值 獲取年齡最大值Optional<Student> max = students.stream().max((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()));Optional<Student> max1 = students.stream().max(Comparator.comparingInt(Student::getAge));System.out.println(max);//Optional[Student{name='王五', age=74, money=6666.0, status=BUSY}]System.out.println(max1);//Optional[Student{name='王五', age=74, money=6666.0, status=BUSY}]// min——返回流中最小值 獲取錢最少的System.out.println(students.stream().min((s1, s2) -> Double.compare(s1.getMoney(), s2.getMoney())).get());//Student{name='小付', age=16, money=1000.0, status=BUSY}}}//狀態(tài) enum Status{FREE,BUSY,VOCATION; }class Student{private String name;private Integer age;private Double money;private Status status;public Student() {}public Student(String name, Integer age, Double money,Status status) {this.name = name;this.age = age;this.money = money;this.status = status;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}public Status getStatus() {return status;}public void setStatus(Status status) {this.status = status;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", money=" + money +", status=" + status +'}';} }

    歸約

    reduce(T identity,BinaryOperator) / reduce(BinaryOperator)—可以將流中元素反復(fù)結(jié)合起來,得到一個值。

    public class StreamDemo {public static void main(String[] args) {/* 歸約 reduce(T identity,BinaryOperator) / reduce(BinaryOperator)—可以將流中元素反復(fù)結(jié)合起來,得到一個值。*/List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//reduce(T identity,BinaryOperator) / reduce(BinaryOperator)—可以將流中元素反復(fù)結(jié)合起來,得到一個值。//案列疊加集合中的值//T reduce(T identity, BinaryOperator<T> accumulator); identity 開始作為x, accumulator用于后面累加Integer reduce = integers.stream().reduce(0, (x, y) -> x + y);System.out.println(reduce);//55List<String> strings = Arrays.asList("a", "b", "c");//拼接集合中的字符串Optional<String> reduce1 = strings.stream().reduce((x, y) -> x + y);System.out.println(reduce1.get());List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//案列,將學生的錢累加起來 // Double aDouble = students.stream().map(Student::getMoney).reduce((x, y) -> x + y).get();Double aDouble = students.stream().map(Student::getMoney).reduce(Double::sum).get();System.out.println(aDouble);//43218.0}}

    備注: map和reduce的連接通常稱為map-reduce模式,因Google用它來進行網(wǎng)絡(luò)搜索而出名。

    收集

    collect—將流轉(zhuǎn)換為其他形式。接收一個Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法

    Collector接口中方法的實現(xiàn)決定了如何對流執(zhí)行收集操作(如收集到 List、Set、Map)。但是 Collectors實用類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見收集器實例。

    收集demo

    public class StreamDemo {public static void main(String[] args) {/*收集 collect—將流轉(zhuǎn)換為其他形式。接收一個Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//案例:按照Student的年齡大于50的名字收集起來List<String> collect = students.stream().filter(student -> student.getAge() > 50).map(Student::getName).collect(Collectors.toList());collect.forEach(System.out::println);//張三 王五//收集年齡大于40的名字并且去重姓名students.stream().filter(student -> student.getAge()>40).map(Student::getName).collect(Collectors.toSet()).forEach(System.out::println);//張三 王五 田七//收集年齡大于20的錢的總個數(shù)Long collect1 = students.stream().filter(student -> student.getAge() > 20).map(Student::getMoney).collect(Collectors.counting());System.out.println(collect1);//5//s收集年齡大于30 的錢的平均數(shù)Double collect2 = students.stream().filter(student -> student.getAge() > 30).map(Student::getMoney).collect(Collectors.averagingDouble(Double::shortValue));System.out.println(collect2);//7221.5//收集工資總和Double collect3 = students.stream().map(Student::getMoney).collect(Collectors.summingDouble(Double::doubleValue)); // Double collect3 = students.stream().map(Student::getMoney).mapToDouble(Double::doubleValue).sum();System.out.println(collect3);//43218.0//收集錢最大值的學生Optional<Student> collect4 = students.stream().collect(Collectors.maxBy((x, y) -> Double.compare(x.getMoney(), y.getMoney()))); // Optional<Student> collect4 = students.stream().collect(Collectors.maxBy(Comparator.comparingDouble((x) -> x.getMoney()))); // Optional<Student> collect4 = students.stream().max(Comparator.comparingDouble(Student::getMoney));System.out.println(collect4.get());//Student{name='田七', age=45, money=8888.0, status=BUSY}//收集錢最小值的金額 // Optional<Double> collect5 = students.stream().map(Student::getMoney).collect(Collectors.minBy((x, y) -> Double.compare(x, y)));Optional<Double> collect5 = students.stream().map(Student::getMoney).min(Comparator.comparingDouble((Double::doubleValue)));System.out.println(collect5.get());//1000.0}}

    collect分組案例

    public class StreamDemo {public static void main(String[] args) {/*收集 collect—將流轉(zhuǎn)換為其他形式。接收一個Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//分組//案例:按照學生狀態(tài)分組Map<Status, List<Student>> statusListMap = students.stream().collect(Collectors.groupingBy(Student::getStatus));//輸出一下System.out.println(statusListMap);//結(jié)果:{VOCATION=[Student{name='趙六', age=12, money=7777.0, status=VOCATION}, Student{name='田七', age=46, money=8888.0, status=VOCATION}],// BUSY=[Student{name='小付', age=16, money=1000.0, status=BUSY}, Student{name='張三', age=56, money=4444.0, status=BUSY}, Student{name='王五', age=74, money=6666.0, status=BUSY}, Student{name='田七', age=45, money=8888.0, status=BUSY}],// FREE=[Student{name='李四', age=23, money=5555.0, status=FREE}]}//多級分組//案例,先根據(jù)學生狀態(tài)分組,在根據(jù)年齡分為青年 中年 老年Map<Status, Map<String, List<Student>>> collect = students.stream().collect(Collectors.groupingBy(Student::getStatus, Collectors.groupingBy(student -> {if (student.getAge() <= 35) {return "青年";} else if (student.getAge() <= 50) {return "中年";} else {return "老年";}})));System.out.println(collect); /* { VOCATION={ 青年=[Student{name='趙六', age=12, money=7777.0, status=VOCATION}], 中年=[Student{name='田七', age=46, money=8888.0, status=VOCATION}]}, BUSY={ 青年=[Student{name='小付', age=16, money=1000.0, status=BUSY}], 老年=[Student{name='張三', age=56, money=4444.0, status=BUSY}, Student{name='王五', age=74, money=6666.0, status=BUSY}], 中年=[Student{name='田七', age=45, money=8888.0, status=BUSY}]}, FREE={ 青年=[Student{name='李四', age=23, money=5555.0, status=FREE}]}}*/}}

    分區(qū) 案例

    public class StreamDemo {public static void main(String[] args) {/*收集 collect—將流轉(zhuǎn)換為其他形式。接收一個Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//分區(qū)//案例:錢大于5000的分為一個區(qū),小于5000的分為一個區(qū)//滿足條件的一個區(qū),不滿足的一個區(qū)Map<Boolean, List<Student>> collect = students.stream().collect(Collectors.partitioningBy(student -> student.getMoney() >= 5000));System.out.println(collect); /* {false=[Student{name='小付', age=16, money=1000.0, status=BUSY}, Student{name='張三', age=56, money=4444.0, status=BUSY}], true=[Student{name='李四', age=23, money=5555.0, status=FREE}, Student{name='王五', age=74, money=6666.0, status=BUSY}, Student{name='趙六', age=12, money=7777.0, status=VOCATION}, Student{name='田七', age=45, money=8888.0, status=BUSY}, Student{name='田七', age=46, money=8888.0, status=VOCATION}]}*/}}

    收集 summarizingDouble案例

    public class StreamDemo {public static void main(String[] args) {/*收集 collect—將流轉(zhuǎn)換為其他形式。接收一個Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//收集 summarizingDoubleDoubleSummaryStatistics collect = students.stream().collect(Collectors.summarizingDouble(Student::getMoney));//getMax getMin getSum getCount getAverageSystem.out.println(collect.getMax());System.out.println(collect.getMin());System.out.println(collect.getSum());System.out.println(collect.getCount());System.out.println(collect.getAverage());}}

    收集 joining 案例

    public class StreamDemo {public static void main(String[] args) {/*收集 collect—將流轉(zhuǎn)換為其他形式。接收一個Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法*/List<Student> students = Arrays.asList(new Student("小付", 16, 1000.00,Status.BUSY),new Student("張三", 56, 4444.00,Status.BUSY),new Student("李四", 23, 5555.00,Status.FREE),new Student("王五", 74, 6666.00,Status.BUSY),new Student("趙六", 12, 7777.00,Status.VOCATION),new Student("田七", 45, 8888.00,Status.BUSY),new Student("田七", 46, 8888.00,Status.VOCATION));//收集 joining 案例:將學生名字加起來用,號拼接String collect = students.stream().map(Student::getName).collect(Collectors.joining(","));System.out.println(collect);//小付,張三,李四,王五,趙六,田七,田七} }

    并行流與順序流

    并行流就是把一個內(nèi)容分成多個數(shù)據(jù)塊,并用不同的線程分別處理每個數(shù)據(jù)塊的流。

    Java 8中將并行進行了優(yōu)化,我們可以很容易的對數(shù)據(jù)進行并行操作。Stream API可以聲明性地通過paralle1() 與sequential()在并行流與順序流之間進行切換。

    了解Fork/Join框架

    Fork/Join框架:就是在必要的情況下,將一個大任務(wù),進行拆分(fork)成若干個小任務(wù)(拆到不可再拆時),再將一個個的小任務(wù)運算的結(jié)果進行 join匯總.

    Optional類

    Optional<T〉類(java.util.Optional)是一個容器類,代表一個值存在或不存在,原來用null表示一個值不存在,現(xiàn)在Optional可以更好的表達這個概念。并且可以避免空指針異常。

    常用方法:

    Optional.of(T t):創(chuàng)建一個 Optional實例
    Optional.empty() :創(chuàng)建一個空的Optional 實例
    Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建Optional實例,否則創(chuàng)建空實例
    isPresent() :判斷是否包含值
    orElse(T t) :如果調(diào)用對象包含值,返回該值,否則返回t
    orElseGet(Supplier s):如果調(diào)用對象包含值,返回該值,否則返回s獲取的值
    map(Function f):如果有值對其處理,并返回處理后的Optional,否則返回Optional.empty()
    flatMap(Function mapper): 與map類似,要求返回值必須是Optional

    Optional 常用方法

    //Optional類 public class OptionalDemo {public static void main(String[] args) {/*Optional類常用方法 Optional.of(T t):創(chuàng)建一個 Optional實例 Optional.empty() :創(chuàng)建一個空的Optional 實例 Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建Optional實例,否則創(chuàng)建空實例 isPresent() :判斷是否包含值 orElse(T t) :如果調(diào)用對象包含值,返回該值,否則返回t orElseGet(Supplier s):如果調(diào)用對象包含值,返回該值,否則返回s獲取的值 map(Function f):如果有值對其處理,并返回處理后的Optional,否則返回Optional.empty() flatMap(Function mapper): 與map類似,要求返回值必須是Optional*///Optional.of(T t):創(chuàng)建一個 Optional實例Optional<Student> studentOptional = Optional.of(new Student("小付",26,1000.00,Status.BUSY));System.out.println(studentOptional.get());//Student{name='小付', age=26, money=1000.0, status=BUSY}//直接傳遞null // Optional<Object> optionalNull = Optional.of(null);//這里發(fā)生Exception in thread "main" java.lang.NullPointerException // System.out.println(optionalNull.get());//Optional.empty() :創(chuàng)建一個空的Optional 實例Optional<Object> empty = Optional.empty(); // System.out.println(empty.get());//這里發(fā)生Exception in thread "main" java.util.NoSuchElementException: No value present//Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建Optional實例,否則創(chuàng)建空實例Optional<Object> optional = Optional.ofNullable(null); // System.out.println(optional.get());//這里發(fā)生Exception in thread "main" java.util.NoSuchElementException: No value present//isPresent() :判斷是否包含值Optional<Student> studentOptional1 = Optional.of(new Student("小付",26,1000.00,Status.BUSY));boolean present = studentOptional1.isPresent();System.out.println(present);//trueOptional<Object> optional2 = Optional.ofNullable(null);boolean present1 = optional2.isPresent();System.out.println(present1);//false//orElse(T t) :如果調(diào)用對象包含值,返回該值,否則返回tOptional<String> name = Optional.of("小付");String rName = name.orElse("返回值");System.out.println(rName);//小付Optional<Object> empty1 = Optional.empty();System.out.println(empty1.orElse("返回值"));//返回值//orElseGet(Supplier s):如果調(diào)用對象包含值,返回該值,否則返回s獲取的值Optional<Integer> integer = Optional.of(1);Integer integer1 = integer.orElseGet(() -> 2);System.out.println(integer1);//1 因為Optional容器有值,就返回容器值,Optional<Object> empty2 = Optional.empty();Object o = empty2.orElseGet(() -> 2);System.out.println(o);//2 因為Optional容為空,就返回get的值2//map(Function f):如果有值對其處理,并返回處理后的Optional,否則返回Optional.empty()Optional<String> s = Optional.of("小付也要快樂呀!");Optional<String> s2 = s.map(s1 -> s.get() + "==");System.out.println(s2.get());//小付也要快樂呀!== 因為Optional有值,就對值進行處理后返回Optional<Object> o1 = Optional.ofNullable(null);Optional<Object> o2 = o1.map(obj -> obj);System.out.println(o2.get());//Exception in thread "main" java.util.NoSuchElementException: No value present 因為是Optional.empty()所以發(fā)生異常//flatMap(Function mapper): 與map類似,要求返回值必須是OptionalOptional<String> aaa = Optional.of("aaa");Optional<Optional<String>> optionalOptional = aaa.flatMap(sss -> Optional.of(s));} }

    5.接口中的默認方法與靜態(tài)方法

    Java 8中允許接口中包含具有具體實現(xiàn)的方法,該方法稱為“默認方法”,默認方法使用default關(guān)鍵字修飾。

    接口默認方法的”類優(yōu)先”原則

    若一個接口中定義了一個默認方法,而另外一個父類或接口中又定義了一個同名的方法時
    選擇父類中的方法。如果一個父類提供了具體的實現(xiàn),那么接口中具有相同名稱和參數(shù)的默認方法會被忽略。

    接口沖突

    接口沖突。如果一個父接口提供一個默認方法,而另一個接口也提供了一個具有相同名稱和參數(shù)列表的方法(不管方法是否是默認方法),那么必須覆蓋該方法來解決沖突

    java8接口新特性代碼demo

    package com.fs.fun;public class MyClass {public static void main(String[] args) {MyClassDemo myClassDemo = new MyClassDemo();System.out.println(myClassDemo.get());//調(diào)用接口的靜態(tài)方法MyFun.show();} }/* 若一個接口中定義了一個默認方法,而另外一個父類或接口中又定義了一個==同名的方法==時 選擇父類中的方法。如果一個父類提供了具體的實現(xiàn),那么接口中具有相同名稱和參數(shù)的默認方法會被忽略。*/ /*class MyClassDemo extends MyC implements MyFun{}*/class MyClassDemo implements MyFun,MyInterface{/*接口沖突。如果一個父接口提供一個默認方法,而另一個接口也提供了一個具有相同名稱和參數(shù)列表的方法(不管方法是否是默認方法),那么必須覆蓋該方法來解決沖突*/@Overridepublic String get() {return MyFun.super.get();} } class MyC{public String get(){return "MyC";} }interface MyFun {//Java 8中允許接口中包含具有具體實現(xiàn)的方法,該方法稱為“默認方法”,默認方法使用`default`關(guān)鍵字修飾。default String get(){return "MyFun";}//接口中的靜態(tài)方法public static void show(){System.out.println("MyFun的靜態(tài)方法");} }interface MyInterface {//Java 8中允許接口中包含具有具體實現(xiàn)的方法,該方法稱為“默認方法”,默認方法使用`default`關(guān)鍵字修飾。default String get(){return "MyInterface";} }

    6.新時間日期API

    使用LocaIDate、LocalTime、LocalDateTime

    LocalDate、LocalTime、 LocalDateTime類的實例是不可變的對象,分別表示使用ISO-8601日歷系統(tǒng)的日期、時間、日期和時間。它們提供了簡單的日期或時間,并不包含當前的時間信息。也不包含與時區(qū)相關(guān)的信息。

    注:ISO-8601日歷系統(tǒng)是國際標準化組織制定的現(xiàn)代公民的日期和時間的表示法

    代碼演示

    public class DateDemo {public static void main(String[] args) {// 使用LocaIDate、LocalTime、LocalDateTimeLocalDateTime now = LocalDateTime.now();System.out.println(now);LocalDateTime of = LocalDateTime.of(2015, 10, 19, 13, 22, 33);System.out.println(of);//加上1月 還有plusYears plusWeeks 加上年 周 十分秒等apiLocalDateTime localDateTime = now.plusMonths(1);System.out.println(localDateTime);//獲取為這一年的那一天int dayOfYear = now.getDayOfYear();System.out.println(dayOfYear);//獲取這個月的那一天int dayOfMonth = now.getDayOfMonth();System.out.println(dayOfMonth);//獲取年 還有很多類似的apiint year = now.getYear();System.out.println(year);/* 2021-07-25T10:31:42.791 2015-10-19T13:22:33 2021-08-25T10:31:42.791 206 25 2021*/} }

    使用 Instant 時間戳

    public class DateDemo {public static void main(String[] args) {// 使用 Instant :時間戳(以Unix元年:1970年1月1日00:00:00到某個時間之間的毫秒值)Instant now = Instant.now();//默認是一UTC時區(qū)System.out.println(now);//2021-07-25T02:34:12.867Z//指定差8個時差的偏移量OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));System.out.println(offsetDateTime);//2021-07-25T10:35:53.832+08:00//轉(zhuǎn)成時間戳System.out.println(now.toEpochMilli());//1627180630630} }

    Duration : 計算兩個"“時間”之間的間隔’ Period : 計算兩個“日期”之間的間隔

    public class DateDemo {public static void main(String[] args) throws InterruptedException {// 使用 Duration : 計算兩個"“時間”之間的間隔' Period : 計算兩個“日期”之間的間隔Instant now = Instant.now();Thread.sleep(100);Instant now2 = Instant.now();//Duration : 計算兩個"“時間”之間的間隔'Duration between = Duration.between(now, now2);/**** toDays()* toHours()* toMillis()* toNanos()*///輸出2個時間之間的毫秒值System.out.println(between.toMillis());LocalTime now3 = LocalTime.now();Thread.sleep(1000);LocalTime now4 = LocalTime.now();// Duration : 計算兩個"“時間”之間的間隔'System.out.println(Duration.between(now3, now4).toMillis());LocalDate date = LocalDate.of(2015,1,1);LocalDate date2 = LocalDate.now();//Period : 計算兩個“日期”之間的間隔Period between1 = Period.between(date, date2);System.out.println(between1.getYears());System.out.println(between1.getMonths());System.out.println(between1.getDays());} }

    日期的操縱

    TemporalAdjuster:時間校正器。有時我們可能需要獲取例如:將日期調(diào)整到“下個周日”等操作。

    TemporalAdjusters:該類通過靜態(tài)方法提供了大量的常用TemporalAdjuster的實現(xiàn)。

    例如獲取下個周日:

    時區(qū)的處理

    Java8中加入了對時區(qū)的支持,帶時區(qū)的時間為分別為:ZonedDate、ZonedTime、ZonedDateTime
    其中每個時區(qū)都對應(yīng)著ID,地區(qū)ID都為“{區(qū)域}/{城市}”的格式

    例如: Asia/Shanghai 等

    Zoneld:該類中包含了所有的時區(qū)信息getAvailableZonelds():可以獲取所有時區(qū)時區(qū)信息of(id):用指定的時區(qū)信息獲取Zoneld對象

    7.其他新特性

    重復(fù)注解與類型注解

    Java 8對注解處理提供了兩點改進:可重復(fù)的注解及可用于類型的注解。

    總結(jié)

    以上是生活随笔為你收集整理的学习笔记之-java8的新特性-函数式接口,lambda表达式,方法引用,Stream API,Optional类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。