学习笔记之-java8的新特性-函数式接口,lambda表达式,方法引用,Stream API,Optional类
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);}
語法格式五:若 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ī)則為:
lambda表達式的使用前提:
1.必須有接口參與: 2.接口必須有且僅有一個抽象方法-->函數(shù)式接口 3.接口必須作為方法的參數(shù)使用2.函數(shù)式接口
函數(shù)式接口
1.必須是接口
2.接口中必須有且僅有一個抽象方法
3.可以用注解驗證是不是函數(shù)式接口–>@FunctionalInterface
Java內(nèi)置四大核心函數(shù)式接口
Consumer<T> :消費型接口
void accept(T t);
supplier<T>∶:供給型接口
T get();
Function<T,R>:函數(shù)型接口
R apply(T t);
Predicate<T> :斷言型接口
boolean test(T t);
其他接口
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
構(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ù)元素
代碼演示
映射
map—接收Lambda ,將元素轉(zhuǎn)換成其他形式或提取信息。接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素。
代碼案例
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——返回流中最小值
代碼演示
歸約
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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习笔记之-MySql高级之sql优化
- 下一篇: 学习笔记之-Kubernetes(K8S