本文目錄一覽:
java8的特性有哪些
Lambda表達式(也稱為閉包)它允許我們將函數當成參數傳遞給某個方法,或者把代碼本身當作數據處理
Java 8使用兩個新概念擴展了介面的含義:默認方法和靜態方法。
方法引用使得開發者可以直接引用現存的方法、Java類的構造方法或者實例對象。方法引用和Lambda表達式配合使用,使得java類的構造方法看起來緊湊而簡潔,沒有很多複雜的模板代碼。
重複註解,Java 8中使用@Repeatable註解定義重複註解
Java 8編譯器在類型推斷方面有很大的提升,在很多場景下編譯器可以推導出某個參數的數據類型,從而使得代碼更為簡潔。
Java 8拓寬了註解的應用場景。
Java 8增加了很多新的工具類(date/time類),並擴展了現存的工具類,以支持現代的並發編程、函數式編程等。
java8中的字元串的用法
1.
首先String不屬於8種基本數據類型,String是一個對象。
因為對象的默認值是null,所以String的默認值也是null;但它又是一種特殊的對象,有其它對象沒有的一些特性。
2.
new String()和new String(「」)都是申明一個新的空字元串,是空串不是null;
3.
String str=」kvill」;
String
str=new String (「kvill」);的區別:
在這裡,我們不談堆,也不談棧,只先簡單引入常量池這個簡單的概念。
常量池(constant
pool)指的是在編譯期被確定,並被保存在已編譯的.class文件中的一些數據。它包括了關於類、方法、介面等中的常量,也包括字元串常量。
看例1:
String
s0=」kvill」;
String
s1=」kvill」;
String
s2=」kv」 + 「ill」;
System.out.println(
s0==s1 );
System.out.println(
s0==s2 );
結果為:
true
true
首先,我們要知道Java會確保一個字元串常量只有一個拷貝。
因為例子中的s0和s1中的」kvill」都是字元串常量,它們在編譯期就被確定了,所以s0==s1為true;而」kv」和」ill」也都是字元串常量,當一個字元串由多個字元串常量連接而成時,它自己肯定也是字元串常量,所以s2也同樣在編譯期就被解析為一個字元串常量,所以s2也是常量池中
」kvill」的一個引用。
所以我們得出s0==s1==s2;
用new
String() 創建的字元串不是常量,不能在編譯期就確定,所以new String() 創建的字元串不放入常量池中,它們有自己的地址空間。
看例2:
String
s0=」kvill」;
String
s1=new String(」kvill」);
String
s2=」kv」 + new String(「ill」);
System.out.println(
s0==s1 );
System.out.println(
s0==s2 );
System.out.println(
s1==s2 );
結果為:
false
false
false
例2中s0還是常量池中」kvill」的應用,s1因為無法在編譯期確定,所以是運行時創建的新對象」kvill」的引用,s2因為有後半部分new
String(「ill」)所以也無法在編譯期確定,所以也是一個新創建對象」kvill」的應用;明白了這些也就知道為何得出此結果了。
4.
String.intern():
再補充介紹一點:存在於.class文件中的常量池,在運行期被JVM裝載,並且可以擴充。String的intern()方法就是擴充常量池的一個方法;當一個String實例str調用intern()方法時,Java查找常量池中是否有相同Unicode的字元串常量,如果有,則返回其的引用,如果沒有,則在常量池中增加一個Unicode等於str的字元串並返回它的引用;看例3就清楚了
例3:
String
s0= 「kvill」;
String
s1=new String(」kvill」);
String
s2=new String(「kvill」);
System.out.println(
s0==s1 );
System.out.println(
「**********」 );
s1.intern();
s2=s2.intern();
//把常量池中「kvill」的引用賦給s2
System.out.println(
s0==s1);
System.out.println(
s0==s1.intern() );
System.out.println(
s0==s2 );
結果為:
false
**********
false
//雖然執行了s1.intern(),但它的返回值沒有賦給s1
true
//說明s1.intern()返回的是常量池中」kvill」的引用
true
最後我再破除一個錯誤的理解:
有人說,「使用String.intern()方法則可以將一個String類的保存到一個全局String表中,如果具有相同值的Unicode字元串已經在這個表中,那麼該方法返回表中已有字元串的地址,如果在表中沒有相同值的字元串,則將自己的地址註冊到表中「如果我把他說的這個全局的
String表理解為常量池的話,他的最後一句話,「如果在表中沒有相同值的字元串,則將自己的地址註冊到表中」是錯的:
看例4:
String
s1=new String(“kvill”);
String
s2=s1.intern();
System.out.println(
s1==s1.intern() );
System.out.println(
s1+” “+s2 );
System.out.println(
s2==s1.intern() );
結果:
false
kvill
kvill
true
在這個類中我們沒有聲名一個」kvill」常量,所以常量池中一開始是沒有」kvill」的,當我們調用s1.intern()後就在常量池中新添加了一個」kvill」常量,原來的不在常量池中的」kvill」仍然存在,也就不是「將自己的地址註冊到常量池中」了。
s1==s1.intern()為false說明原來的「kvill」仍然存在;
s2現在為常量池中「kvill」的地址,所以有s2==s1.intern()為true。
5.
關於equals()和==:
這個對於String簡單來說就是比較兩字元串的Unicode序列是否相當,如果相等返回true;而==是比較兩字元串的地址是否相同,也就是是否是同一個字元串的引用。
6.
關於String是不可變的
這一說又要說很多,大家只要知道String的實例一旦生成就不會再改變了,比如說:String
str=」kv」+」ill」+」 「+」ans」;
就是有4個字元串常量,首先」kv」和」ill」生成了」kvill」存在內存中,然後」kvill」又和」
「 生成 」kvill 「存在內存中,最後又和生成了」kvill
ans」;並把這個字元串的地址賦給了str,就是因為String的「不可變」產生了很多臨時變數,這也就是為什麼建議用StringBuffer的原因了,因為StringBuffer是可改變的。
Java8有哪些新特性
jdk1.8的新特性包括如下:
一、介面的默認方法與靜態方法,也就是介面中可以有實現方法
二、Lambda 表達式
三、函數式介面與靜態導入
四、Lambda 作用域
在lambda表達式中訪問外層作用域和老版本的匿名對象中的方式很相似。你可以直接訪問標記了final的外層局部變數,或者實例的欄位以及靜態變數。
五、訪問局部變數,等等其他新特性。
Java8的特性有哪些
1、函數式介面
Java 8 引入的一個核心概念是函數式介面(Functional Interfaces)。通過在介面裡面添加一個抽象方法,這些方法可以直接從介面中運行。如果一個介面定義個唯一一個抽象方法,那麼這個介面就成為函數式介面。同時,引入了一個新的註解:@FunctionalInterface。可以把他它放在一個介面前,表示這個介面是一個函數式介面。這個註解是非必須的,只要介面只包含一個方法的介面,虛擬機會自動判斷,不過最好在介面上使用註解 @FunctionalInterface 進行聲明。在介面中添加了 @FunctionalInterface 的介面,只允許有一個抽象方法,否則編譯器也會報錯。
java.lang.Runnable 就是一個函數式介面。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
2、Lambda 表達式
函數式介面的重要屬性是:我們能夠使用 Lambda 實例化它們,Lambda 表達式讓你能夠將函數作為方法參數,或者將代碼作為數據對待。Lambda 表達式的引入給開發者帶來了不少優點:在 Java 8 之前,匿名內部類,監聽器和事件處理器的使用都顯得很冗長,代碼可讀性很差,Lambda 表達式的應用則使代碼變得更加緊湊,可讀性增強;Lambda 表達式使並行操作大集合變得很方便,可以充分發揮多核 CPU 的優勢,更易於為多核處理器編寫代碼;
Lambda 表達式由三個部分組成:第一部分為一個括弧內用逗號分隔的形式參數,參數是函數式介面裡面方法的參數;第二部分為一個箭頭符號:-;第三部分為方法體,可以是表達式和代碼塊。語法如下:
1. 方法體為表達式,該表達式的值作為返回值返回。
(parameters) – expression
2. 方法體為代碼塊,必須用 {} 來包裹起來,且需要一個 return 返回值,但若函數式介面裡面方法返回值是 void,則無需返回值。
(parameters) – { statements; }
例如,下面是使用匿名內部類和 Lambda 表達式的代碼比較。
下面是用匿名內部類的代碼:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.print(“Helllo Lambda in actionPerformed”);
}
});
下面是使用 Lambda 表達式後:
button.addActionListener(
\\actionPerformed 有一個參數 e 傳入,所以用 (ActionEvent e)
(ActionEvent e)-
System.out.print(“Helllo Lambda in actionPerformed”)
);
上面是方法體包含了參數傳入 (ActionEvent e),如果沒有參數則只需 ( ),例如 Thread 中的 run 方法就沒有參數傳入,當它使用 Lambda 表達式後:
Thread t = new Thread(
\\run 沒有參數傳入,所以用 (), 後面用 {} 包起方法體
() – {
System.out.println(“Hello from a thread in run”);
}
);
通過上面兩個代碼的比較可以發現使用 Lambda 表達式可以簡化代碼,並提高代碼的可讀性。
為了進一步簡化 Lambda 表達式,可以使用方法引用。例如,下面三種分別是使用內部類,使用 Lambda 表示式和使用方法引用方式的比較:
//1. 使用內部類
FunctionInteger, String f = new FunctionInteger,String(){
@Override
public String apply(Integer t) {
return null;
}
};
//2. 使用 Lambda 表達式
FunctionInteger, String f2 = (t)-String.valueOf(t);
//3. 使用方法引用的方式
FunctionInteger, String f1 = String::valueOf;
要使用 Lambda 表達式,需要定義一個函數式介面,這樣往往會讓程序充斥著過量的僅為 Lambda 表達式服務的函數式介面。為了減少這樣過量的函數式介面,Java 8 在 java.util.function 中增加了不少新的函數式通用介面。例如:
FunctionT, R:將 T 作為輸入,返回 R 作為輸出,他還包含了和其他函數組合的默認方法。
PredicateT :將 T 作為輸入,返回一個布爾值作為輸出,該介面包含多種默認方法來將 Predicate 組合成其他複雜的邏輯(與、或、非)。
ConsumerT :將 T 作為輸入,不返回任何內容,表示在單個參數上的操作。
例如,People 類中有一個方法 getMaleList 需要獲取男性的列表,這裡需要定義一個函數式介面 PersonInterface:
interface PersonInterface {
public boolean test(Person person);
}
public class People {
private ListPerson persons= new ArrayListPerson();
public ListPerson getMaleList(PersonInterface filter) {
ListPerson res = new ArrayListPerson();
persons.forEach(
(Person person) –
{
if (filter.test(person)) {//調用 PersonInterface 的方法
res.add(person);
}
}
);
return res;
}
}
為了去除 PersonInterface 這個函數式介面,可以用通用函數式介面 Predicate 替代如下:
class People{
private ListPerson persons= new ArrayListPerson();
public ListPerson getMaleList(PredicatePerson predicate) {
ListPerson res = new ArrayListPerson();
persons.forEach(
person – {
if (predicate.test(person)) {//調用 Predicate 的抽象方法 test
res.add(person);
}
});
return res;
}
}
3、介面的增強
Java 8 對介面做了進一步的增強。在介面中可以添加使用 default 關鍵字修飾的非抽象方法。還可以在介面中定義靜態方法。如今,介面看上去與抽象類的功能越來越類似了。
默認方法
Java 8 還允許我們給介面添加一個非抽象的方法實現,只需要使用 default 關鍵字即可,這個特徵又叫做擴展方法。在實現該介面時,該默認擴展方法在子類上可以直接使用,它的使用方式類似於抽象類中非抽象成員方法。但擴展方法不能夠重載 Object 中的方法。例如:toString、equals、 hashCode 不能在介面中被重載。
例如,下面介面中定義了一個默認方法 count(),該方法可以在子類中直接使用。
public interface DefaultFunInterface {
//定義默認方法 countdefault int count(){
return 1;
}
}
public class SubDefaultFunClass implements DefaultFunInterface {
public static void main(String[] args){
//實例化一個子類對象,改子類對象可以直接調用父介面中的默認方法 count
SubDefaultFunClass sub = new SubDefaultFunClass();
sub.count();
}
}
靜態方法
在介面中,還允許定義靜態的方法。介面中的靜態方法可以直接用介面來調用。
例如,下面介面中定義了一個靜態方法 find,該方法可以直接用 StaticFunInterface .find() 來調用。
public interface StaticFunInterface {public static int find(){
return 1;
}
}
public class TestStaticFun {
public static void main(String[] args){
//介面中定義了靜態方法 find 直接被調用
StaticFunInterface.fine();
}
}
java8是java18嗎
是。Java8於2014年3月18日發布,截止到2022年12月16日,當前最新發行版本是Java18,所以是,Java是一門面向對象的編程語言,不僅吸收了C++語言的各種優點,還摒棄了C++里難以理解的多繼承、指針等概念,因此Java語言具有功能強大和簡單易用兩個特徵。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/296082.html