??博客x主頁(yè):己不由心王道長(zhǎng)??!
??文章說(shuō)明:JDK8新特性??
?系列專欄:Java基礎(chǔ)
??本篇內(nèi)容:對(duì)JDK8的新特性進(jìn)行學(xué)習(xí)和講解??
??每日一語(yǔ):這個(gè)世界本來(lái)就不完美,如果我們?cè)俨唤邮懿煌昝赖淖约?,那我們要怎么活??
?? 交流社區(qū):己不由心王道長(zhǎng)(優(yōu)質(zhì)編程社區(qū))
一、Java發(fā)展史
1.1 發(fā)展史
Sun公司在1991年成立了一個(gè)稱為綠色計(jì)劃( Green Project )的項(xiàng)目,由James Gosling(高斯林)博土領(lǐng)導(dǎo),綠色計(jì)劃的目的是開發(fā)一種能夠在各種消費(fèi)性電子產(chǎn)品(機(jī)頂盒、冰箱、收音機(jī)等)上運(yùn)行的程序架構(gòu)。這個(gè)項(xiàng)目的產(chǎn)品就是Java語(yǔ)言的前身: Oak(橡樹)。Oak當(dāng)時(shí)在消費(fèi)品市場(chǎng)上并不算成功,但隨著1995年互聯(lián)網(wǎng)潮流的興起,Oak迅速找到了最適合自己發(fā)展的市場(chǎng)定位。
- JDK Beta - 1995v
- JDK 1.0 - 1996年1月 (真正第一個(gè)穩(wěn)定的版本JDK 1.0.2,被稱作 Java 1 )
- JDK 1.1 - 1997年2月
- J2SE 1.2 - 1998年12月
- J2ME(Java 2 Micro Edition,Java 2平臺(tái)的微型版),應(yīng)用于移動(dòng)、無(wú)線及有限- 資源的環(huán)境。
- J2SE(Java 2 Standard Edition,Java 2平臺(tái)的標(biāo)準(zhǔn)版),應(yīng)用于桌面環(huán)境。
- J2EE(Java 2 Enterprise Edition,Java 2平臺(tái)的企業(yè)版),應(yīng)用于基于Java的應(yīng)用服務(wù)器。
- J2SE 1.3 - 2000年5月
- J2SE 1.4 - 2002年2月
- J2SE 5.0 - 2004年9月
- Java SE 6 - 2006年12月
- Java SE 7 - 2011年7月
- Java SE 8(LTS) - 2014年3月
- Java SE 9 - 2017年9月
- Java SE 10(18.3) - 2018年3月
- Java SE 11(18.9 LTS) - 2018年9月
- Java SE 12(19.3) - 2019年3月
- Java SE 13(19.9) - 2019年9月
- Java SE 14(20.3) - 2020年3月
- Java SE 15(20.9) - 2020年9月
我們可以看到Java SE的主要版本大約每?jī)赡臧l(fā)布一次,直到Java SE 6到Java SE 7開始花了五年時(shí)間,之后又花了三年時(shí)間到達(dá)Java SE 8。
1.2 OpenJDK和OracleJDK
1.2.1 Open JDK來(lái)源:
Java 由 Sun 公司發(fā)明,Open JDK是Sun在2006年末把Java開源而形成的項(xiàng)目。也就是說(shuō)Open JDK是Java SE平臺(tái)版的開源和免費(fèi)實(shí)現(xiàn),它由 SUN 和 Java 社區(qū)提供支持,2009年 Oracle 收購(gòu)了 Sun 公司,自此 Java 的維護(hù)方之一的SUN 也變成了 Oracle
1.2.2 Open JDK 和 Oracle JDK的關(guān)系:
大多數(shù) JDK 都是在 Open JDK 的基礎(chǔ)上進(jìn)一步編寫實(shí)現(xiàn)的,比如 IBM J9, Oracle JDK 和 Azul Zulu,Azul Zing。
Oracle JDK完全由 Oracle 公司開發(fā),Oracle JDK是基于Open JDK源代碼的商業(yè)版本。此外,它包含閉源組件。Oracle JDK根據(jù)二進(jìn)制代碼許可協(xié)議獲得許可,在沒(méi)有商業(yè)許可的情況下,在2019年1月之后發(fā)布的Oracle Java SE 8的公開更新將無(wú)法用于商業(yè)或生產(chǎn)用途。但是 Open JDK是完全開源的,可以自由使用。
1.3 Open JDK 官網(wǎng)介紹
Open JDK 官網(wǎng): http://openjdk.java.net/ 。
JDK Enhancement Proposals(JDK增強(qiáng)建議)。通俗的講JEP就是JDK的新特性.
小結(jié):
Oracle JDK是基于Open JDK源代碼的商業(yè)版本。我們要學(xué)習(xí)Java新技術(shù)可以去Open JDK 官網(wǎng)學(xué)習(xí)。
二、Lambda表達(dá)式
在最開始我們先創(chuàng)建一個(gè)maven工程,很多東西需要添加依賴
2.1 需求分析
創(chuàng)建一個(gè)新的線程,指定線程要執(zhí)行的任務(wù):
package com.daozhang;
/**
* @Author Administrator
* @Date 2023/6/24 20:19
* @description
* @Version 1.0
*/
public class application {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("測(cè)試線程執(zhí)行代碼:"+Thread.currentThread().getName());
}
}).start();
System.out.println("主線程執(zhí)行的代碼:"+Thread.currentThread().getName());
}
}
代碼分析:
- Thread類需要一個(gè)Runnable接口作為參數(shù)(線程的實(shí)現(xiàn)有三種實(shí)現(xiàn)方式),其中的抽象方法run方法是用來(lái)指定線程任務(wù)內(nèi)容的核心。
- 為了指定run方法體,不得不需要Runnable的實(shí)現(xiàn)類。
- 為了省去定義一個(gè)Runnable 的實(shí)現(xiàn)類,不得不使用匿名內(nèi)部類。
- 必須覆蓋重寫抽象的run方法,所有的方法名稱,方法參數(shù),方法返回值不得不都重寫一遍,而且不能出錯(cuò)。
- 而實(shí)際上,我們只在乎方法體中的代碼。
2.2 Lamada表達(dá)式的體驗(yàn)
Lambda表達(dá)式是一個(gè)匿名函數(shù),可以理解為一段可以傳遞的代碼。
new Thread(() -> { System.out.println("新線程Lambda表達(dá)式..."
+Thread.currentThread().getName()); })
.start();
Lambda表達(dá)式的優(yōu)點(diǎn):簡(jiǎn)化了匿名內(nèi)部類的使用,語(yǔ)法更加簡(jiǎn)單。匿名內(nèi)部類語(yǔ)法冗余,體驗(yàn)了Lambda表達(dá)式后,發(fā)現(xiàn)Lambda表達(dá)式是簡(jiǎn)化匿名內(nèi)部類的一種方式。
2.3 Lambda表達(dá)式的語(yǔ)法規(guī)則
實(shí)際上Lambda省去了面向?qū)ο蟮臈l條框框,Lambda的標(biāo)準(zhǔn)格式由3個(gè)部分組成:
(參數(shù)類型 參數(shù)名稱) -> {
代碼體;
}
格式說(shuō)明:
- (參數(shù)類型 參數(shù)名稱):參數(shù)列表
- {代碼體;} :方法體
- -> : 箭頭,分割參數(shù)列表和方法體
2.3.1 Lambda表達(dá)式練習(xí)
一、練習(xí)無(wú)參無(wú)返回值的Lambda:
1.1 首先定義一個(gè)接口:
package com.daozhang.student;
/**
* @Author Administrator
* @Date 2023/6/24 20:31
* @description 定義一個(gè)Lambda表達(dá)式學(xué)生接口
* @Version 1.0
*/
public interface Student {
void gotoSchool();//大學(xué)生,主打一個(gè)喜歡上學(xué)
}
1.2 然后我們?cè)谥鞣椒▌?chuàng)建使用:
//在這里我們調(diào)用loveComeToSchool,首先接口肯定是不能new的,這時(shí)候肯定是匿名方式
//1、傳統(tǒng)方式(匿名內(nèi)部類方式)
loveComeToSchool(new Student() {
@Override
public void gotoSchool() {
System.out.println("匿名內(nèi)部類方式上學(xué):"+Thread.currentThread().getName());
}
});
//2、Lambda表達(dá)式方式
loveComeToSchool(()->{
System.out.println("Lambda表達(dá)式方式,同樣上學(xué)");
});
1.3 結(jié)果展示:
匿名內(nèi)部類方式上學(xué):main
Lambda表達(dá)式方式,同樣上學(xué)
1.4小結(jié):可以看到,Lambda表達(dá)式十分簡(jiǎn)潔
2.3.2 Lambda表達(dá)式練習(xí)
二、練習(xí)有參無(wú)返回值的Lambda:
Java有兩種方法,有參和無(wú)參,無(wú)參說(shuō)了,聊聊有參!
2.1、創(chuàng)建對(duì)象
2.1.1這里使用到了Lombok,先導(dǎo)入依賴:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.1.2、person類:
package com.daozhang.pojos;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author Administrator
* @Date 2023/6/24 20:47
* @description
* @Version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String name;
private Integer age;
private Integer high;
}
2.1.3、然后我們?cè)贚ist集合中保存多個(gè)Person對(duì)象,然后對(duì)這些對(duì)象做根據(jù)age排序操作
package com.daozhang;
import com.daozhang.pojos.Person;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @Author Administrator
* @Date 2023/6/24 20:47
* @description
* @Version 1.0
*/
public class test02 {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("王道長(zhǎng)",18,185));//男神!??!
list.add(new Person("諸葛青",20,183));//不聽(tīng)八卦
list.add(new Person("不要碧蓮",19,182));//月下光觀鳥
list.add(new Person("寶兒姐",18,168)); //阿威十八式
//使用Collections對(duì)list進(jìn)行排序
//1、傳統(tǒng)方式
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
//按照年齡排序
return o1.getAge()-o2.getAge();
}
});
System.out.println("傳統(tǒng):");
for(Person person:list){
System.out.println(person);
}
//2、Lambda方式
Collections.sort(list,(Person o1,Person o2)->{
return o1.getAge()-o2.getAge();
});
System.out.println("Lambda:");
for(Person person:list){
System.out.println(person);
}
}
}
結(jié)果:
"C:\Program Files\Java\jdk1.8.0_102\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2021.3.2\lib\idea_rt.jar=7588:D:\idea\IntelliJ IDEA 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_102\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_102\jre\lib\rt.jar;D:\JDK8\JDK8\target\classes" com.daozhang.test02
傳統(tǒng):
Person(name=王道長(zhǎng), age=18, high=185)
Person(name=寶兒姐, age=18, high=168)
Person(name=不要碧蓮, age=19, high=182)
Person(name=諸葛青, age=20, high=183)
Lambda:
Person(name=王道長(zhǎng), age=18, high=185)
Person(name=寶兒姐, age=18, high=168)
Person(name=不要碧蓮, age=19, high=182)
Person(name=諸葛青, age=20, high=183)
Process finished with exit code 0
2.4 Lambda表達(dá)式的使用前提
可以看出,Lambda表達(dá)式的語(yǔ)法十分簡(jiǎn)潔,但是Lambda表達(dá)式不是隨便使用的,使用的使用有幾個(gè)條件我們需要特別注意:
一、方法的參數(shù)或局部變量類型必須為接口才能使用Lambda。
二、接口中有且只有一個(gè)抽象方法(在第五小段會(huì)提及一個(gè)注解@FunctionalInterfa)
2.5 @FunctionalInterface注解
我們?cè)谏厦嫣峒埃琇ambda表達(dá)式接口中有且只有一個(gè)抽象方法,那么我們?cè)趺醋龅竭@一點(diǎn)呢?就是使用FunctionalInterface注解修飾
package com.daozhang.student;
/**
* @Author Administrator
* @Date 2023/6/24 20:31
* @description 定義一個(gè)Lambda表達(dá)式學(xué)生接口
* @Version 1.0
*/
@FunctionalInterface
public interface Student {
/**
* @FunctionalInterface:一個(gè)標(biāo)準(zhǔn)注解,被該注解修飾的接口只能聲明一個(gè)抽象方法
*/
void gotoSchool();
}
2.6 Lambda表達(dá)式的原理
匿名內(nèi)部類的原理:匿名內(nèi)部類的本質(zhì)是在編譯時(shí)生成一個(gè)Class 文件。XXXXX$1.class
package com.daozhang;
import com.daozhang.student.Student;
/**
* @Author Administrator
* @Date 2023/6/24 20:19
* @description
* @Version 1.0
*/
public class test01 {
public static void main(String[] args) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// System.out.println("測(cè)試線程執(zhí)行代碼:"+Thread.currentThread().getName());
// }
// }).start();
// System.out.println("主線程執(zhí)行的代碼:"+Thread.currentThread().getName());
//在這里我們調(diào)用loveComeToSchool,首先接口肯定是不能new的,這時(shí)候肯定是匿名方式
//1、傳統(tǒng)方式(匿名內(nèi)部類方式)
loveComeToSchool(new Student() {
@Override
public void gotoSchool() {
System.out.println("匿名內(nèi)部類方式上學(xué):"+Thread.currentThread().getName());
}
});
//2、Lambda表達(dá)式方式
loveComeToSchool(()->{
System.out.println("Lambda表達(dá)式方式,同樣上學(xué)");
});
}
public static void loveComeToSchool(Student student){
student.gotoSchool();
}
}
還可以通過(guò)反編譯工具來(lái)查看生成的代碼 XJad 工具來(lái)查看:
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space
// Source File Name: test01.java
package com.daozhang;
import com.daozhang.student.Student;
import java.io.PrintStream;
// Referenced classes of package com.daozhang:
// test01
static class test01$1
implements Student
{
public void gotoSchool()
{
System.out.println((new StringBuilder()).append("匿名內(nèi)部類方式上學(xué):").append(Thread.currentThread().getName()).toString());
}
test01$1()
{
}
}
那么Lambda表達(dá)式的原理是什么呢?我們也通過(guò)反編譯工具來(lái)查看:不僅看不了,還關(guān)不了!??!
解決辦法:ctrl+alt+'.'打開任務(wù)管理器,找到對(duì)應(yīng)位置選擇結(jié)束任務(wù)
那我們?cè)趺捶淳幾gLambda表達(dá)式的字節(jié)碼文件呢?,使用JDK自帶的javap命令
- javap -c -p 文件名.class
-c:表示對(duì)代碼進(jìn)行反匯編
-p:顯示所有的類和成員
反匯編結(jié)果:
final class com.daozhang.test02$1 implements java.util.Comparator<com.daozhang.pojos.Person> {
com.daozhang.test02$1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public int compare(com.daozhang.pojos.Person, com.daozhang.pojos.Person);
Code:
0: aload_1
1: invokevirtual #2 // Method com/daozhang/pojos/Person.getAge:()Ljava/lang/Integer;
4: invokevirtual #3 // Method java/lang/Integer.intValue:()I
7: aload_2
8: invokevirtual #2 // Method com/daozhang/pojos/Person.getAge:()Ljava/lang/Integer;
11: invokevirtual #3 // Method java/lang/Integer.intValue:()I
14: isub
15: ireturn
public int compare(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #4 // class com/daozhang/pojos/Person
5: aload_2
6: checkcast #4 // class com/daozhang/pojos/Person
9: invokevirtual #5 // Method compare:(Lcom/daozhang/pojos/Person;Lcom/daozhang/pojos/Person;)I
12: ireturn
}
小結(jié):
匿名內(nèi)部類在編譯的時(shí)候會(huì)產(chǎn)生一個(gè)class文件。
Lambda表達(dá)式在程序運(yùn)行的時(shí)候會(huì)形成一個(gè)類。
- 在類中新增了一個(gè)方法,這個(gè)方法的方法體就是Lambda表達(dá)式中的代碼。
- 還會(huì)形成一個(gè)匿名內(nèi)部類,實(shí)現(xiàn)接口,重寫抽象方法。
- 在接口中重寫方法會(huì)調(diào)用新生成的方法。
2.7 Lambda表達(dá)式的省略寫法
在lambda表達(dá)式的標(biāo)準(zhǔn)寫法基礎(chǔ)上,可以使用省略寫法的規(guī)則為:
- 小括號(hào)內(nèi)的參數(shù)類型可以省略
- 如果小括號(hào)內(nèi)有且僅有一個(gè)參數(shù),則小括號(hào)可以省略
- 如果大括號(hào)內(nèi)有且僅有一個(gè)語(yǔ)句,可以同時(shí)省略大括號(hào),return 關(guān)鍵字及語(yǔ)句分號(hào)。
package com.daozhang;
import com.daozhang.student.Student;
/**
* @Author Administrator
* @Date 2023/6/25 18:52
* @description
* @Version 1.0
*/
public class test03 {
public static void main(String[] args) {
//省略寫法一:省略參數(shù)、大括號(hào)
gotos(()->System.out.println("上學(xué)去了"));
}
public static void gotos(Student student){
student.gotoSchool();
}
}
結(jié)果:
上學(xué)去了
2.8 Lambda表達(dá)式和內(nèi)部類的區(qū)別
Lambda和匿名內(nèi)部類的對(duì)比
- 所需類型不一樣
匿名內(nèi)部類的類型可以是 類,抽象類,接口
Lambda表達(dá)式需要的類型必須是接口 - 抽象方法的數(shù)量不一樣
匿名內(nèi)部類所需的接口中的抽象方法的數(shù)量是隨意的
Lambda表達(dá)式所需的接口中只能有一個(gè)抽象方法 - 實(shí)現(xiàn)原理不一樣
匿名內(nèi)部類是在編譯后形成一個(gè)class
Lambda表達(dá)式是在程序運(yùn)行的時(shí)候動(dòng)態(tài)生成class
三、接口的增強(qiáng)
3.1 JDK8接口新增
一、JDK8之前:
interface 接口名{
1、靜態(tài)常量
2、抽象方法
};
二、JDK8之后: 可以有默認(rèn)方法和靜態(tài)方法
interface 接口名{
1、靜態(tài)常量;
2、抽象方法;
3、默認(rèn)方法;
4、靜態(tài)方法;
}
3.2 默認(rèn)方法
一、為什么要有默認(rèn)方法?
在JDK8以前接口中只能有抽象方法和靜態(tài)常量,會(huì)存在以下的問(wèn)題:
如果接口中新增抽象方法,那么實(shí)現(xiàn)類都必須要抽象這個(gè)抽象方法,非常不利于接口的擴(kuò)展的:
當(dāng)接口只有一個(gè)方法時(shí),實(shí)現(xiàn)類去重寫:
package com.daozhang;
/**
* @Author Administrator
* @Date 2023/6/25 19:33
* @description
* @Version 1.0
*/
public class test04 {
public static void main(String[] args) {
}
}
interface animal{
void eat();
}
class cat implements animal{
@Override
public void eat() {
}
}
class dog implements animal{
@Override
public void eat() {
}
}
當(dāng)接口有很多方法時(shí),實(shí)現(xiàn)類也可以重寫,但是每一個(gè)實(shí)現(xiàn)類都去重寫它不需要的方法,這合理嗎?:
package com.daozhang;
/**
* @Author Administrator
* @Date 2023/6/25 19:33
* @description
* @Version 1.0
*/
public class test04 {
public static void main(String[] args) {
}
}
interface animal{
void run();
void sing();
void eat();
}
class cat implements animal{
//必須重寫,不然報(bào)錯(cuò)
@Override
public void eat() {
}
}
class dog implements animal{
//必須重寫,不然報(bào)錯(cuò)
@Override
public void eat() {
}
}
可以看出,上面接口顯然不符合我們的要求,所以在JDK8之后,就引入(增加)了默認(rèn)方法。
二、默認(rèn)方法的格式
以下是默認(rèn)方法的格式:
interface 接口名{
修飾符 default 返回值類型 方法名{
方法體;
}
}
默認(rèn)方法就是你想重寫就重寫,不重寫也不會(huì)強(qiáng)制你實(shí)現(xiàn)
package com.daozhang;
/**
* @Author Administrator
* @Date 2023/6/25 19:33
* @description
* @Version 1.0
*/
public class test04 {
public static void main(String[] args) {
animal cat = new cat();
cat.gotoSchool();
}
}
interface animal{
void eat();
public default String gotoSchool(){
System.out.println("誰(shuí)說(shuō)動(dòng)物不用上學(xué)的?");
return null;
}
}
class cat implements animal{
@Override
public void eat() {
}
}
class dog implements animal{
@Override
public void eat() {
}
}
二、接口中默認(rèn)方法的使用:
- 接口中的默認(rèn)方法有兩種使用方式
-
- 實(shí)現(xiàn)類直接調(diào)用接口的默認(rèn)方法
-
- 實(shí)現(xiàn)類重寫接口的默認(rèn)方法
3.3 靜態(tài)方法
一、在JDK8中在接口中增加了靜態(tài)方法,作用同樣是為了增加接口的擴(kuò)展性
二、語(yǔ)法規(guī)則:
interface 接口名{
修飾符 static 返回值類型 方法名{
方法體;
}
}
package com.daozhang;
/**
* @Author Administrator
* @Date 2023/6/25 19:33
* @description
* @Version 1.0
*/
public class test04 {
public static void main(String[] args) {
animal cat = new cat();
cat.gotoSchool();
}
}
interface animal{
void eat();
public default String gotoSchool(){
System.out.println("誰(shuí)說(shuō)動(dòng)物不用上學(xué)的?");
return null;
}
public static void makeFriend(){
System.out.println("想找個(gè)女朋友");
}
}
class cat implements animal{
@Override
public void eat() {
}
}
class dog implements animal{
@Override
public void eat() {
}
}
靜態(tài)方法的使用:
接口中的靜態(tài)方法在實(shí)現(xiàn)類中是不能被重寫的,調(diào)用的話只能通過(guò)接口類型來(lái)實(shí)現(xiàn): 接口名.靜態(tài)方法名();
注意:這里是不能重寫,而不是不需要
3.4 兩個(gè)方法之間的區(qū)別
- 默認(rèn)方法通過(guò)實(shí)例調(diào)用,靜態(tài)方法通過(guò)接口名調(diào)用
- 默認(rèn)方法可以被繼承,實(shí)現(xiàn)類可以直接調(diào)用接口默認(rèn)方法,也可以重寫接口默認(rèn)方法
- 靜態(tài)方法不能被繼承,實(shí)現(xiàn)類不能重寫接口的靜態(tài)方法,只能使用接口名調(diào)用
四、函數(shù)式接口
4.1 函數(shù)式接口的由來(lái)
我們知道使用Lambda表達(dá)式的前提是需要有函數(shù)式接口,而Lambda表達(dá)式使用時(shí)不關(guān)心接口名,抽象方法名。只關(guān)心抽象方法的參數(shù)列表和返回值類型。因此為了讓我們使用Lambda表達(dá)式更加的方法,在JDK中提供了大量常用的函數(shù)式接口。
/**
* @Author Administrator
* @Date 2023/6/25 21:01
* @description
* @Version 1.0
*/
public class functionTest01 {
public static void main(String[] args) {
funSum(arr->{
int sum = 0;
for(int i:arr){
sum+=i;
}
return sum;
});
}
public static void funSum(Operator operator){
int[] arr ={5,6,7,8,9};
int sum = operator.getArr(arr);
System.out.println(sum);
}
}
/*
* 函數(shù)式接口
*/
@FunctionalInterface
interface Operator{
int getArr(int[] arr);
}
4.2 函數(shù)式接口的介紹
在JDK中幫我們提供的有函數(shù)式接口,主要是在 java.util.function 包中。
4.2.1 Supplier
一、無(wú)參有返回值的接口,對(duì)于的Lambda表達(dá)式需要提供一個(gè)返回?cái)?shù)據(jù)的類型。
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
二、簡(jiǎn)單使用
/**
* @Author Administrator
* @Date 2023/6/25 21:17
* @description
* @Version 1.0
*/
public class Supplier {
public static void main(String[] args) {
fun(()->{
int[] arr = {250,361,520};
Arrays.sort(arr);
return arr[arr.length-1];
});
}
public static void fun(java.util.function.Supplier<Integer> supplier){
Integer number = supplier.get();
System.out.println(number);
}
}
4.2.2 Consumer
一、有參無(wú)返回值得接口,前面介紹的Supplier接口是用來(lái)生產(chǎn)數(shù)據(jù)的,而Consumer接口是用來(lái)消費(fèi)數(shù)據(jù)的,使用的時(shí)候需要指定一個(gè)泛型來(lái)定義參數(shù)類型。
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
二、簡(jiǎn)單使用
/**
* @Author Administrator
* @Date 2023/6/25 21:49
* @description
* @Version 1.0
*/
public class ConsumerTest {
public static void main(String[] args) {
fun2((t)->{
//在方法體有動(dòng)作才會(huì)執(zhí)行方法,否則不會(huì)執(zhí)行方法
System.out.println(t);
});
}
public static void fun2(Consumer<String> consumer){
consumer.accept("唱跳rap");
}
}
默認(rèn)方法:andThen
如果一個(gè)方法的參數(shù)和返回值全部是Consumer類型,那么就可以實(shí)現(xiàn)效果,消費(fèi)一個(gè)數(shù)據(jù)的時(shí)候,首先做一個(gè)操作,然后再做一個(gè)操作,實(shí)現(xiàn)組合,而這個(gè)方法就是Consumer接口中的default方法
andThen方法
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
測(cè)試:
/**
* @Author Administrator
* @Date 2023/6/25 22:08
* @description
* @Version 1.0
*/
public class ConsumerAndThenTest {
public static void main(String[] args) {
Test2(msg1->{
//轉(zhuǎn)大寫
System.out.println(msg1.toUpperCase());
},msg2->{
//轉(zhuǎn)小寫
System.out.println(msg2.toLowerCase());
});
}
public static void Test2(Consumer<String> t1,Consumer<String> t2){
String str = "Out of control";
t2.andThen(t1).accept(str);
}
}
結(jié)果:
out of control
OUT OF CONTROL
分析,觀察到與我們?cè)谡{(diào)用的時(shí)候?qū)懙捻樞虿灰粯樱瑸槭裁茨兀?/strong>
原理:
我們?cè)?span id="n5n3t3z" class="token class-name">Test2方法里使用的是t2.andThen(t1),也就是在t2作為參數(shù)傳遞執(zhí)行對(duì)應(yīng)的方法之后執(zhí)行t1,andThen的意思就是什么之后做這件事情。
4.2.3 Function
有參有返回值的接口,F(xiàn)unction接口是根據(jù)一個(gè)類型的數(shù)據(jù)得到另一個(gè)類型的數(shù)據(jù),前者稱為前置條件,后者稱為后置條件。有參數(shù)有返回值。
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
使用:輸入一個(gè)字符串,返回一個(gè)整數(shù)。
/**
* @Author Administrator
* @Date 2023/6/25 22:35
* @description
* @Version 1.0
*/
public class FunctionTest {
public static void main(String[] args) {
Test04((arg)->{
Integer res = Integer.valueOf(arg);
return res;
});
}
public static void Test04(Function<String,Integer> function){
int gif = function.apply("18");
System.out.println(gif);
}
}
結(jié)果:
18
默認(rèn)方法:andThen,也是用來(lái)進(jìn)行組合操作。
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*
* @see #compose(Function)
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
使用:
/**
* @Author Administrator
* @Date 2023/6/25 22:49
* @description
* @Version 1.0
*/
public class FunctionAndThenTest {
public static void main(String[] args) {
fun(arg1->{
return Integer.valueOf(arg1);
},arg2->{
return arg2*10;
});
}
public static void fun(Function<String,Integer> t1,Function<Integer,Integer> t2){
int res = t1.andThen(t2).apply("18");
System.out.println(res);
}
}
注意,由于t1——》t2具有傳遞性,所有t2的 泛型要跟t1轉(zhuǎn)換后的泛型對(duì)應(yīng)
默認(rèn)的compose方法的作用順序和andThen方法剛好相反
而靜態(tài)方法identity則是,輸入什么參數(shù)就返回什么參數(shù)
4.2.4 Predicate
有參且返回值為Boolean的接口
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
使用:
/**
* @Author Administrator
* @Date 2023/6/25 23:00
* @description
* @Version 1.0
*/
public class PredicateTest {
public static void main(String[] args) {
fun((arg)->{
boolean res = arg.equals("不需要嗎?");
return res;
});
}
public static void fun(Predicate<String> msg){
boolean res = msg.test("愛(ài)一個(gè)人需要理由嗎?");
System.out.println(res);
}
}
其他擴(kuò)展方法:
/**
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* Returns a composed predicate that represents a short-circuiting logical
* OR of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**
* Returns a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
在Predicate中的默認(rèn)方法提供了邏輯關(guān)系操作 and or negate isEquals方法:
使用:
/**
* @Author Administrator
* @Date 2023/6/25 23:09
* @description
* @Version 1.0
*/
public class PredicateDemoTest {
public static void main(String[] args) {
fun(arg1->{
return arg1.contains("愛(ài)");
},arg2->{
return arg2.contains("pf");
});
}
public static void fun(Predicate<String> arg1,Predicate<String> arg2){
boolean And = arg1.and(arg2).test("不說(shuō)一句的愛(ài)有多好");
boolean Or = arg1.or(arg2).test("不說(shuō)一句的愛(ài)有多好");
boolean Negate = arg1.negate().test("不說(shuō)一句的愛(ài)有多好");
System.out.println(And);
System.out.println(Or);
System.out.println(Negate);
}
}
結(jié)果:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-500702.html
false
true
false
結(jié)語(yǔ)
寫到這里總字?jǐn)?shù)也有兩萬(wàn)+了,然后覺(jué)得文章太長(zhǎng),看的人恐怕不多,一般就看看就劃走了,故而分為上下兩部,上部就先到函數(shù)式接口。歸根結(jié)底,只有練習(xí)才能真正理解用法和體會(huì)這種思維,加油。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-500702.html
到了這里,關(guān)于JDK8新特性-上部的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!