今天我來聊聊 Java8 的一些新的特性,確實(shí) Java8 的新特性的出現(xiàn),給開發(fā)者帶來了非常大的便利,可能剛剛開始的時(shí)候會有點(diǎn)不習(xí)慣的這種寫法,但是,當(dāng)你真正的熟悉了之后,你一定會愛上這些新的特性的,這篇文章就來聊聊這些新特性。
10年積累的網(wǎng)站建設(shè)、做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先制作網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有右江免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
lambda 表達(dá)式在項(xiàng)目中也是用到了,這種新的語法的加入,對于使用 Java 多年的我,我覺得是如虎添翼的感覺哈,這種新的語法,大大的改善了以前的 Java 的代碼,變得更加的簡潔,我覺得這也是為什么 Java8 能夠很快的流行起來的原因吧。
這里我們用幾個(gè)以前的經(jīng)典的 Java 的寫法和用 lambda 表達(dá)式的方式進(jìn)行對比。
線程的用法
原始的線程用法
//使用匿名內(nèi)部類的方式啟動多線程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("這是使用匿名內(nèi)部類的方式。。。");
}
}).start();
lambda 表達(dá)式
//使用lambda表達(dá)式方式
new Thread(() -> {
System.out.println("這是使用lambda表達(dá)式的方式。。。");
}).start();
你會發(fā)現(xiàn),用 lambda 表達(dá)式的方式能夠?qū)懜俚拇a,看起來也會更加的舒服和簡潔。
這里沒有使用參數(shù),只是一個(gè)簡單的例子。
我們再看一個(gè)例子。
遍歷方式
原始方式
//原始方式
List list = Arrays.asList(1, 2, 3, 4, 5);
for (int i : list) {
System.out.println(i);
}
lambda 表達(dá)式方式
//使用lambda表達(dá)式代替foreach循環(huán)
Stream.of(1, 2, 3, 4, 5).forEach((x) -> {
System.out.println(x);
});
在原始的方式中,我們一般使用 foreach 的方式進(jìn)行遍歷,有了 Java8 的方式之后,我們可以用 forEach
方法,然后,再用 lambda 表達(dá)式的方式進(jìn)行遍歷,也讓原來的方式變得更加的簡潔。
在這個(gè)例子中,我們加了一個(gè)參數(shù),在()
中間我們加了一個(gè) x
,代表的意思其實(shí)是:通過 forEach
方法,我們把一個(gè)元素已經(jīng)賦值到 x
中了,拿到這個(gè) x
,我們就可以輸出結(jié)果。
總結(jié)
lambda 的使用方式其實(shí)很簡單,可以總結(jié)為下面的方法。
([參數(shù)可選,...]) -> {
}
方法引用其實(shí)是 lambda 表達(dá)式的部分的簡化,也就是為了簡化 lambda 表達(dá)式而存在的感覺,下面我們還講講怎么使用方法引用。
/**
* @return void
* @Author ouyangsihai
* @Description 方法引用測試
* @Date 10:23 2019/5/14
* @Param []
**/
@Test
public void test_method_reference() {
//使用lambda表達(dá)式
Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
.map(s -> s.length()) //lambda
.forEach((x) -> {
System.out.println(x);
});
//使用靜態(tài)方法引用
Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
.map(String::length) //靜態(tài)方法引用
.forEach((x) -> {
System.out.println(x);
});
//使用實(shí)例方法引用
Stream.of(
new ClassMate("1", "歐陽思海"),
new ClassMate("2", "sihai")
).map(ClassMate::getName)//實(shí)例方法引用
.forEach(x -> {
System.out.println(x);
});
}
在第一個(gè)測試中,我們用的是 lambda 表達(dá)式來獲取每個(gè)字符串的長度。
s -> s.length()
在第二個(gè)測試中,我們使用的是靜態(tài)方法引用來獲取每個(gè)字符串的長度。
String::length
在第三個(gè)測試中,我們使用的是實(shí)例方法引用。
ClassMate::getName
解釋
① map 方法是映射的意思。
② forEach 方式是遍歷每一個(gè)元素。
③ ClassMate 是一個(gè)包含 id 和 name 的簡單 po 類。
通過上面這個(gè)例子,基本上我們就知道怎么使用方法引用了。下面我們進(jìn)行一個(gè)小的總結(jié)。
總結(jié)
① 使用方法
類名::方法名
② 方法可以是:靜態(tài)方法,實(shí)例方法
在上面我們講了方法引用的基本使用方法,其實(shí)除了方法引用以外,還有構(gòu)造函數(shù)引用,回想一下,以前我們創(chuàng)建對象是怎么做?是不是需要 new 一個(gè)對象呢,那么現(xiàn)在用構(gòu)造函數(shù)引用又是怎么做的呢?
下面我們用一個(gè)例子講解一下,在這個(gè)例子中,對象還是使用上面的 ClassMate
。
/**
* @return void
* @Author ouyangsihai
* @Description 構(gòu)造函數(shù)引用測試
* @Date 10:23 2019/5/14
* @Param []
**/
@Test
public void test_method_reference2() {
//使用lambda表達(dá)式
Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
.map(s -> new ClassMate(s)) //lambda
.collect(Collectors.toList());
//使用構(gòu)造函數(shù)引用
Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
.map(ClassMate::new) //構(gòu)造函數(shù)引用,由上下文決定用哪一個(gè)構(gòu)造函數(shù)
.collect(Collectors.toList());
}
① 第一個(gè)我們使用的是 lambda 表達(dá)式進(jìn)行創(chuàng)建對象的 s -> new ClassMate(s)
。
② 第二個(gè)我們使用的是構(gòu)造函數(shù)引用創(chuàng)建對象的 ClassMate::new
。
③ 我們發(fā)現(xiàn)構(gòu)造函數(shù)引用:類名::new
,然后對于使用哪一個(gè)構(gòu)造函數(shù)是由上下文決定的,比如有一個(gè)參數(shù)和兩個(gè)參數(shù)和無參數(shù)的構(gòu)造函數(shù),會自動確定用哪一個(gè)。
在 Java 8 之前的接口是不能有實(shí)現(xiàn)的,只能定義抽象方法,然而,在 Java 8 以后,增加了一個(gè)新的功能,可以添加實(shí)現(xiàn),可以定義默認(rèn)方法,可以定義靜態(tài)方法。
什么是函數(shù)式接口呢?
這個(gè)名詞在 Java 中以前是很少聽到的,但是正是有了 Java 8 的橫空出世,函數(shù)式編程也變得熟悉了。
在一個(gè)接口中我們以 @FunctionalInterface
注解聲明一個(gè)接口,并且接口中只有一個(gè)抽象方法,那么我們就叫做這是一個(gè)函數(shù)式接口。
/**
* @ClassName FunctionalInterfaceTest
* @Description
* @Author 歐陽思海
* @Date 2019/5/14 10:39
* @Version 1.0
**/
@FunctionalInterface
public interface FunctionalInterfaceTest {
//繼承接口后,又加了新的抽象方法,這個(gè)接口就不再是函數(shù)式接口
void test(String s);
}
① 上面的接口中只有一個(gè)抽象方法,所以這是一個(gè)函數(shù)式接口。
② 如果上面接口中再加一個(gè)抽象方法,那么就不是函數(shù)式接口了。
下面,我們再通過繼承來繼承這個(gè)接口。
/**
* @ClassName FunctionalTest
* @Description
* @Author 歐陽思海
* @Date 2019/5/17 17:26
* @Version 1.0
**/
public interface FunctionalTest extends FunctionalInterfaceTest{
int test2();
}
① 我們繼承了上面的接口,并且加了一個(gè) test2
方法。
② 這里注意,如果一個(gè)接口集成現(xiàn)有的函數(shù)式接口后,又加了其他的抽象方法,這個(gè)接口就不是函數(shù)式接口了。
默認(rèn)方法很簡單,用 default
聲明即可。
/**
* @ClassName FunctionalInterfaceTest
* @Description
* @Author 歐陽思海
* @Date 2019/5/14 10:39
* @Version 1.0
**/
@FunctionalInterface
public interface FunctionalInterfaceTest {
//繼承接口后,又加了新的抽象方法,這個(gè)接口就不再是函數(shù)式接口
void test(String s);
//默認(rèn)方法
default String getStr(){
return null;
}
}
① 在接口中添加了一個(gè)默認(rèn)方法。并且實(shí)現(xiàn)了方法。
默認(rèn)方法很簡單,用 static
聲明即可。
/**
* @ClassName FunctionalInterfaceTest
* @Description
* @Author 歐陽思海
* @Date 2019/5/14 10:39
* @Version 1.0
**/
@FunctionalInterface
public interface FunctionalInterfaceTest {
//繼承接口后,又加了新的抽象方法,這個(gè)接口就不再是函數(shù)式接口
void test(String s);
//靜態(tài)方法
static String getStr2(){
return null;
}
//錯(cuò)誤用法
default static String getStr3(){
return null;
}
}
① 實(shí)現(xiàn)的靜態(tài)方法,用 static
聲明。
② 注意不能同時(shí)使用 default 和 static 聲明。
在這篇文章中,我們講了 lambda 表達(dá)式、方法引用、函數(shù)式接口、接口中的靜態(tài)方法、接口中的默認(rèn)方法的使用。