Lambda 表達(dá)式
Lambda 是一個(gè)匿名函數(shù),我們可以把 Lambda 表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞)剩檀』劭猓可以寫出更簡(jiǎn)潔、更靈活的代碼。作為一種更緊湊的代碼風(fēng)格麸俘,使Java的語(yǔ)言表達(dá)能力得到了提升辩稽。
Lambda 表達(dá)式在Java 語(yǔ)言中引入了一個(gè)新的語(yǔ)法元素和操作符。這個(gè)操作符為 “->” 从媚, 該操作符被稱為 Lambda 操作符或箭頭操作符搂誉。它將 Lambda 分為兩個(gè)部分:
- 左側(cè):指定了 Lambda 表達(dá)式需要的所有參數(shù)
- 右側(cè):指定了 Lambda 體,即 Lambda 表達(dá)式要執(zhí)行的功能静檬。
Lambda 表達(dá)式語(yǔ)法
語(yǔ)法格式一:無(wú)參炭懊,無(wú)返回值,Lambda 體只需一條語(yǔ)句
Runnable runnable = () -> System.out.println("hello Lambda");
語(yǔ)法格式二:Lambda 需要一個(gè)參數(shù)
Consumer<String> con = (t) -> System.out.println(t);
語(yǔ)法格式三:Lambda 只需要一個(gè)參數(shù)時(shí)拂檩,參數(shù)的小括號(hào)可以省略
Consumer<String> con = t -> System.out.println(t);
語(yǔ)法格式四:Lambda 需要兩個(gè)參數(shù)侮腹,并且有返回值
Comparator<Integer> comparator = (x,y) -> {
? ? ? ? System.out.println("相加結(jié)果是:"+(x+y));
? ? ? ? return Integer.compare(x,y);
? ? };
語(yǔ)法格式五:當(dāng) Lambda 體只有一條語(yǔ)句時(shí),return 與大括號(hào)可以省略
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
語(yǔ)法格式六:數(shù)據(jù)類型可以省略稻励,因?yàn)榭捎删幾g器推斷得出父阻,稱為“類型推斷”
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
類型判斷
Lambda 表達(dá)式中無(wú)需指定類型,程序依然可以編譯望抽,這是因?yàn)?javac 根據(jù)程序的上下文加矛,在后臺(tái)推斷出了參數(shù)的類型。Lambda 表達(dá)式的類型依賴于上下文環(huán)境煤篙,是由編譯器推斷出來(lái)的斟览。這就是所謂的“類型推斷”。
函數(shù)式接口
只包含一個(gè)抽象方法的接口辑奈,稱為函數(shù)式接口苛茂。
可以通過(guò) Lambda 表達(dá)式來(lái)創(chuàng)建該接口的對(duì)象。(若 Lambda 表達(dá)式拋出一個(gè)受檢異常鸠窗,那么該異常需要在目標(biāo)接口的抽象方法上進(jìn)行聲明)妓羊。
我們可以在任意函數(shù)式接口上使用 @FunctionalInterface 注解,這樣做可以檢查它是否是一個(gè)函數(shù)式接口稍计,同時(shí) javadoc 也會(huì)包含一條聲明躁绸,說(shuō)明這個(gè)接口是一個(gè)函數(shù)式接口。
Java 內(nèi)置四大核心函數(shù)式接口
方法引用
當(dāng)要傳遞給Lambda體的操作臣嚣,已經(jīng)有實(shí)現(xiàn)的方法了净刮,可以使用方法引用(實(shí)現(xiàn)抽象方法的參數(shù)列表,必須與方法引用方法的參數(shù)列表保持一致茧球。)方法引用:使用操作符 “::” 將方法名和對(duì)象或類的名字分隔開來(lái)庭瑰。
如下三種主要使用情況:
- 對(duì)象::實(shí)例方法
- 類::靜態(tài)方法
- 類::實(shí)例方法
使用注意事項(xiàng):
* 1.Lambda 體中調(diào)用方法的參數(shù)列表與返回值類型,要與函數(shù)式接口中抽象方法的函數(shù)列表和返回值類型保持一致星持。
* 2.若Lambda 參數(shù)列表中第一個(gè)參數(shù)是實(shí)例方法調(diào)用者,第二個(gè)參數(shù)是實(shí)例方法的參數(shù) 可以使用 ClassName :: method
構(gòu)造器引用
與函數(shù)式接口相結(jié)合抢埋,自動(dòng)與函數(shù)式接口中方法兼容。可以把構(gòu)造器引用賦值給定義的方法揪垄,與構(gòu)造器參數(shù)列表要與接口中抽象方法的參數(shù)列表一致穷吮!
格式: ClassName::new
數(shù)組引用
格式: type[] :: new
? ? /**
? ? * 方法引用:若Lambda 體中的內(nèi)容有方法已經(jīng)實(shí)現(xiàn)了,可以使用"方法引用"
? ? */
? ? public class TestMethodRef {
? ? ? ? @Test
? ? ? ? public void test1(){
? ? ? ? ? ? Consumer<String> con = (x) -> System.out.println(x);
? ? ? ? ? ? con.accept("shuai");
? ? ? ? ? ? //方法引用,對(duì)象::實(shí)例方法名
? ? ? ? ? ? Consumer<String> consumer = System.out::println;
? ? ? ? ? ? consumer.accept("test");
? ? ? ? }
? ? ? ? @Test
? ? ? ? public void test2(){
? ? ? ? ? ? Person person = new Person();
? ? ? ? ? ? Supplier<String> supplier = () -> person.getName();
? ? ? ? ? ? String str = supplier.get();
? ? ? ? ? ? System.err.println(str);
? ? ? ? ? ? //方法引用,對(duì)象::實(shí)例方法名
? ? ? ? ? ? Supplier<Integer> sup = person::getAge;
? ? ? ? ? ? Integer age = sup.get();
? ? ? ? ? ? System.out.println(age);
? ? ? ? }
? ? ? ? //類::靜態(tài)方法名
? ? ? ? @Test
? ? ? ? public void test3(){
? ? ? ? ? ? Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
? ? ? ? ? ? //使用前提,compare的參數(shù)和返回值與Comparator一致
? ? ? ? ? ? Comparator<Integer> comparator = Integer :: compare;
? ? ? ? }
? ? ? ? //類::實(shí)例方法名
? ? ? ? @Test
? ? ? ? public void test4(){
? ? ? ? ? ? BiPredicate<String, String> bp = (x,y) -> x.equals(y);
? ? ? ? ? ? //使用條件:第一個(gè)參數(shù)是實(shí)例方法調(diào)用者,第二個(gè)參數(shù)是實(shí)例方法的參數(shù)
? ? ? ? ? ? BiPredicate<String, String> biPredicate = String :: equals;
? ? ? ? }
? ? ? ? //構(gòu)造器引用
? ? ? ? @Test
? ? ? ? public void test5(){
? ? ? ? ? ? Supplier<Person> sup = () -> new Person();
? ? ? ? ? ? //構(gòu)造器引用方式
? ? ? ? ? ? Supplier<Person> supplier = Person :: new;
? ? ? ? ? ? Person person = supplier.get();
? ? ? ? ? ? System.out.println(person);
? ? ? ? }
? ? ? ? //構(gòu)造器引用
? ? ? ? @Test
? ? ? ? public void test6(){
? ? ? ? ? ? Function<Integer, Person> fun = (x) -> new Person(x);
? ? ? ? ? ? Function<Integer, Person> function = Person :: new;
? ? ? ? ? ? Person person = function.apply(2);
? ? ? ? ? ? System.out.println(person);
? ? ? ? ? ? System.out.println("--------------------");
? ? ? ? ? ? BiFunction<String, Integer, Person> biFunction = Person :: new;
? ? ? ? ? ? Person person2 = biFunction.apply("張三", 23);
? ? ? ? ? ? System.out.println(person2);
? ? ? ? }
? ? ? ? //數(shù)組引用
? ? ? ? @Test
? ? ? ? public void test7(){
? ? ? ? ? ? Function<Integer, String[]> fun = (x) -> new String[x];
? ? ? ? ? ? String[] strs = fun.apply(8);
? ? ? ? ? ? System.out.println(strs.length);
? ? ? ? ? ? Function<Integer, String[]> function = String[] :: new;
? ? ? ? ? ? String[] strArray = function.apply(6);
? ? ? ? ? ? System.out.println(strArray.length);
? ? ? ? }
? ? }
Stream API
Stream 是 Java8 中處理集合的關(guān)鍵抽象概念饥努,它可以指定 希望對(duì)集合進(jìn)行的操作捡鱼,可以執(zhí)行非常復(fù)雜的查找、過(guò)濾和映射數(shù)據(jù)等操作酷愧。使用Stream API 對(duì)集合數(shù)據(jù)進(jìn)行操作驾诈,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫(kù)查詢。也可以使用 Stream API 來(lái)并行執(zhí)行操作溶浴。簡(jiǎn)而言之乍迄,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
Stream
是數(shù)據(jù)渠道士败,用于操作數(shù)據(jù)源(集合闯两、數(shù)組等)所生成的元素序列。
“集合講的是數(shù)據(jù)谅将,流講的是計(jì)算漾狼!”
1. Stream 自己不會(huì)存儲(chǔ)元素。
2. Stream 不會(huì)改變?cè)磳?duì)象饥臂。相反逊躁,他們會(huì)返回一個(gè)持有結(jié)果的新Stream。
3. Stream 操作是延遲執(zhí)行的隅熙。這意味著他們會(huì)等到需要結(jié)果的時(shí)候才執(zhí)行志衣。
Stream 的操作三個(gè)步驟
創(chuàng)建 Stream
一個(gè)數(shù)據(jù)源(如:集合、數(shù)組)猛们,獲取一個(gè)流
中間操作
一個(gè)中間操作鏈念脯,對(duì)數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理
終止操作(終端操作)
一個(gè)終止操作,執(zhí)行中間操作鏈弯淘,并產(chǎn)生結(jié)果
創(chuàng)建Stream?
Java8 中的 Collection 接口被擴(kuò)展绿店,提供了兩個(gè)獲取流的方法:
- default Stream stream() : 返回一個(gè)順序流
- default Stream parallelStream() : 返回一個(gè)并行流
Java8 中的 Arrays 的靜態(tài)方法 stream() 可以獲取數(shù)組流:
- static Stream stream(T[] array): 返回一個(gè)流
可以使用靜態(tài)方法 Stream.of(), 通過(guò)顯示值創(chuàng)建一個(gè)流。它可以接收任意數(shù)量的參數(shù)庐橙。
- public static Stream of(T… values) : 返回一個(gè)流
可以使用靜態(tài)方法 Stream.iterate() 和Stream.generate(), 創(chuàng)建無(wú)限流假勿。
- 迭代
public static Stream iterate(final T seed, final UnaryOperator f)
- 生成
public static Stream generate(Supplier s) :
? ? //創(chuàng)建Stream
? ? @Test
? ? public void test1(){
? ? ? ? //1.可以通過(guò)Collection系列集合提供的stream() 或parallelStream()
? ? ? ? List<String> list = new ArrayList<>();
? ? ? ? Stream<String> stream = list.stream();
? ? ? ? //2.通過(guò)Arrays中靜態(tài)方法 stream() 獲取數(shù)組流
? ? ? ? Person[] persons = new Person[10];
? ? ? ? Stream<Person> stream2 = Arrays.stream(persons);
? ? ? ? //3.通過(guò)Stream類中的靜態(tài)方法 of()
? ? ? ? Stream<String> stream3 = Stream.of("a","b","c");
? ? ? ? //4.創(chuàng)建無(wú)限流
? ? ? ? //迭代
? ? ? ? Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
? ? ? ? stream4.limit(8).forEach(System.out :: println);
? ? ? ? //生成
? ? ? ? Stream.generate(() -> Math.random()).limit(6)
? ? ? ? ? ? .forEach(System.out :: println);
? ? }? ? ?
Stream 的中間操作
多個(gè)中間操作可以連接起來(lái)形成一個(gè)流水線,除非流水線上觸發(fā)終止操作态鳖,否則中間操作不會(huì)執(zhí)行任何的處理转培!而在終止操作時(shí)一次性全部處理,稱為“惰性求值”浆竭。
? ? /**
? ? * Stream API的中間操作
? ? */
? ? public class TestSteamAPI2 {
? ? ? ? List<Person> persons = Arrays.asList(
? ? ? ? ? ? ? ? new Person(2, "錢四", 24),
? ? ? ? ? ? ? ? new Person(1, "張三", 33),
? ? ? ? ? ? ? ? new Person(2, "李四", 24),
? ? ? ? ? ? ? ? new Person(3, "王五", 65),
? ? ? ? ? ? ? ? new Person(4, "趙六", 26),
? ? ? ? ? ? ? ? new Person(5, "陳七", 27)
? ? ? ? );
? ? ? ? //內(nèi)部迭代浸须,由Stream API完成
? ? ? ? @Test
? ? ? ? public void test1(){
? ? ? ? ? ? //中間操作,不會(huì)執(zhí)行任何操作
? ? ? ? ? ? Stream<Person> stream = persons.stream()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .filter((e) -> {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("Stream的中間操作");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return e.getAge() > 25;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? //終止操作惨寿,一次性執(zhí)行全部?jī)?nèi)容,即"惰性求值"
? ? ? ? ? ? stream.forEach(System.out :: println);
? ? ? ? }
? ? ? ? //外部迭代
? ? ? ? @Test
? ? ? ? public void test2(){
? ? ? ? ? ? Iterator<Person> iterator = persons.iterator();
? ? ? ? ? ? while (iterator.hasNext()) {
? ? ? ? ? ? ? ? System.out.println(iterator.next());
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //limit删窒,截?cái)?/p>
? ? ? ? @Test
? ? ? ? public void test3(){
? ? ? ? ? ? persons.stream()
? ? ? ? ? ? ? ? .filter((e) -> {
? ? ? ? ? ? ? ? ? ? System.out.println("迭代操作"); //短路
? ? ? ? ? ? ? ? ? ? return e.getAge() > 24;
? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? .limit(2)
? ? ? ? ? ? ? ? .forEach(System.out :: println);
? ? ? ? }
? ? ? ? //跳過(guò)skip,distinct去重(要重寫equals和hashcode)
? ? ? ? @Test
? ? ? ? public void test4(){
? ? ? ? ? ? persons.stream()
? ? ? ? ? ? ? ? ? ? .filter((e) -> e.getAge() > 23)
? ? ? ? ? ? ? ? ? ? .skip(2)
? ? ? ? ? ? ? ? ? ? .distinct()
? ? ? ? ? ? ? ? ? ? .forEach(System.out :: println);
? ? ? ? }
? ? ? ? //映射
? ? ? ? @Test
? ? ? ? public void test5(){
? ? ? ? ? ? List<String> list = Arrays.asList("a","bb","c","d","e");
? ? ? ? ? ? list.stream().map((str) -> str.toUpperCase())
? ? ? ? ? ? ? ? .forEach(System.out :: println);
? ? ? ? ? ? System.out.println("---------------");
? ? ? ? ? ? persons.stream().map((Person :: getName)).forEach(System.out :: println);
? ? ? ? ? ? System.out.println("---------------");
? ? ? ? ? ? Stream<Stream<Character>> stream = list.stream()
? ? ? ? ? ? ? ? .map(TestSteamAPI2 :: filterCharacter);
? ? ? ? ? ? stream.forEach((s) -> {
? ? ? ? ? ? ? ? s.forEach(System.out :: println);
? ? ? ? ? ? });
? ? ? ? ? ? System.out.println("-----------------");
? ? ? ? ? ? //flatMap
? ? ? ? ? ? Stream<Character> stream2 = list.stream()
? ? ? ? ? ? ? ? .flatMap(TestSteamAPI2 :: filterCharacter);
? ? ? ? ? ? stream2.forEach(System.out :: println);
? ? ? ? }
? ? ? ? //處理字符串
? ? ? ? public static Stream<Character> filterCharacter(String str){
? ? ? ? ? ? List<Character> list = new ArrayList<>();
? ? ? ? ? ? for (Character character : str.toCharArray()) {
? ? ? ? ? ? ? ? list.add(character);
? ? ? ? ? ? }
? ? ? ? ? ? return list.stream();
? ? ? ? }
? ? ? ? //排序
? ? ? ? @Test
? ? ? ? public void test6(){
? ? ? ? ? ? List<String> list = Arrays.asList("bb","c","aa","ee","ddd");
? ? ? ? ? ? list.stream()
? ? ? ? ? ? ? ? .sorted() //自然排序
? ? ? ? ? ? ? ? .forEach(System.out :: println);
? ? ? ? ? ? System.out.println("------------");
? ? ? ? ? ? persons.stream()
? ? ? ? ? ? ? ? ? ? .sorted((p1,p2) -> {
? ? ? ? ? ? ? ? ? ? ? ? if (p1.getAge() == p2.getAge()) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? return p1.getName().compareTo(p2.getName());
? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? return p1.getAge() - p2.getAge();
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }).forEach(System.out :: println);
? ? ? ? }
? ? }
接口中的默認(rèn)方法與靜態(tài)方法
接口中的默認(rèn)方法
Java 8中允許接口中包含具有具體實(shí)現(xiàn)的方法裂垦,該方法稱為“默認(rèn)方法”,默認(rèn)方法使用 default 關(guān)鍵字修飾肌索。
接口默認(rèn)方法的”類優(yōu)先”原則
若一個(gè)接口中定義了一個(gè)默認(rèn)方法蕉拢,而另外一個(gè)父類或接口中又定義了一個(gè)同名的方法時(shí)
- 選擇父類中的方法。如果一個(gè)父類提供了具體的實(shí)現(xiàn)诚亚,那么接口中具有相同名稱和參數(shù)的默認(rèn)方法會(huì)被忽略晕换。
- 接口沖突。如果一個(gè)父接口提供一個(gè)默認(rèn)方法站宗,而另一個(gè)接口也提供了一個(gè)具有相同名稱和參數(shù)列表的方法(不管方法是否是默認(rèn)方法)届巩,那么必須覆蓋該方法來(lái)解決沖突。
接口中的靜態(tài)方法
Java8 中份乒,接口中允許添加靜態(tài)方法恕汇。
? ? public interface MyInterface {
? ? ? ? default String getName(){
? ? ? ? ? ? return "接口測(cè)試";
? ? ? ? }
? ? ? ? public static void show(){
? ? ? ? ? ? System.out.println("接口中的靜態(tài)方法");
? ? ? ? }
? ? }
新特性:
? ? public static void main(String[] args) throws InterruptedException, ExecutionException {
? ? ? ? DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
? ? ? ? Callable<LocalDate> callable = new Callable<LocalDate>() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public LocalDate call() throws Exception {
? ? ? ? ? ? ? ? return LocalDate.parse("20170521",dtf);
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? ExecutorService pool = Executors.newFixedThreadPool(10);
? ? ? ? List<Future<LocalDate>> results = new ArrayList<>();
? ? ? ? for (int i = 0; i < 8; i++) {
? ? ? ? ? ? results.add(pool.submit(callable));
? ? ? ? }
? ? ? ? for (Future<LocalDate> future : results) {
? ? ? ? ? ? System.out.println(future.get());
? ? ? ? }
? ? ? ? //關(guān)閉資源
? ? ? ? pool.shutdown();
}
LocalDate LocalTime LocalDateTime
? ? //1.LocalDate LocalTime LocalDateTime
? ? @Test
? ? public void test1(){
? ? ? ? LocalDateTime ldt = LocalDateTime.now();
? ? ? ? System.out.println(ldt);
? ? ? ? LocalDateTime ldt2 = LocalDateTime.of(2017, 05, 21, 21, 43, 55, 33);
? ? ? ? System.out.println(ldt2);
? ? ? ? LocalDateTime ldt3 = ldt.plusYears(3);
? ? ? ? System.out.println(ldt3);
? ? ? ? LocalDateTime ldt4 = ldt.minusMonths(5);
? ? ? ? System.out.println(ldt4);
? ? }
java.time.format.DateTimeFormatter 類
該類提供了三種格式化方法:
- 預(yù)定義的標(biāo)準(zhǔn)格式
- 語(yǔ)言環(huán)境相關(guān)的格式
- 自定義的格式
? ? //DateTimeFormatter:格式化時(shí)間/日期
? ? @Test
? ? public void test6(){
? ? ? ? DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
? ? ? ? LocalDateTime ldt = LocalDateTime.now();
? ? ? ? System.out.println(ldt);
? ? ? ? String format = ldt.format(dtf);
? ? ? ? System.out.println(format);
? ? ? ? System.out.println("------------");
? ? ? ? DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
? ? ? ? String format2 = dtf2.format(ldt);
? ? ? ? System.out.println(format2);
? ? ? ? LocalDateTime ldt2 = ldt.parse(format2,dtf2);
? ? ? ? System.out.println(ldt2);
? ? }
HashMap:減少碰撞,位置相同時(shí),條件達(dá)到鏈表上超過(guò)8個(gè),總數(shù)超過(guò)64個(gè)時(shí),數(shù)據(jù)結(jié)構(gòu)改為紅黑樹。
ConcurrentHashMap:取消鎖分段或辖,與HashMap相同瘾英,達(dá)到條件時(shí),數(shù)據(jù)結(jié)構(gòu)改為紅黑樹颂暇。
Optional 類(java.util.Optional) 是一個(gè)容器類缺谴,代表一個(gè)值存在或不存在,原來(lái)用 null 表示一個(gè)值不存在耳鸯,現(xiàn)在 Optional 可以更好的表達(dá)這個(gè)概念湿蛔。并且可以避免空指針異常。
常用方法:
- Optional.of(T t) : 創(chuàng)建一個(gè) Optional 實(shí)例
- Optional.empty() : 創(chuàng)建一個(gè)空的 Optional 實(shí)例
- Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建 Optional 實(shí)例,否則創(chuàng)建空實(shí)例
- isPresent() : 判斷是否包含值
- orElse(T t) : 如果調(diào)用對(duì)象包含值县爬,返回該值阳啥,否則返回t
- orElseGet(Supplier s) :如果調(diào)用對(duì)象包含值,返回該值财喳,否則返回 s 獲取的值
- map(Function f): 如果有值對(duì)其處理察迟,并返回處理后的Optional,否則返回 Optional.empty()
- flatMap(Function mapper):與 map 類似耳高,要求返回值必須是Optional
? ? /**
? ? * Optional類
? ? */
? ? public class TestOptional {
? ? ? ? @Test
? ? ? ? public void test1(){
? ? ? ? ? ? //參數(shù)不能為空
? ? ? ? ? ? Optional<Person> op = Optional.of(new Person());
? ? ? ? ? ? Person person = op.get();
? ? ? ? ? ? System.out.println(person);
? ? ? ? }
? ? ? ? @Test
? ? ? ? public void test2(){
? ? ? ? ? ? //構(gòu)建空optional
? ? ? ? ? ? Optional<Person> op = Optional.empty();
? ? ? ? ? ? System.out.println(op.get());
? ? ? ? }
? ? ? ? @Test
? ? ? ? public void test3(){
? ? ? ? ? ? //如果為null扎瓶,調(diào)用empty,如果不為null泌枪,調(diào)用of
? ? ? ? ? ? Optional<Person> op = Optional.ofNullable(null);
? ? //? ? ? Optional<Person> op = Optional.ofNullable(new Person());
? ? ? ? ? ? if (op.isPresent()) {
? ? ? ? ? ? ? ? System.out.println(op.get());
? ? ? ? ? ? }
? ? ? ? ? ? //有值就用值概荷,沒(méi)值就替代
? ? ? ? ? ? Person person = op.orElse(new Person("張三", 23));
? ? ? ? ? ? System.out.println(person);
? ? ? ? }
? ? }
Java 8對(duì)注解處理提供了兩點(diǎn)改進(jìn):可重復(fù)的注解及可用于類型的注解。
? ? @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
? ? @Retention(RetentionPolicy.RUNTIME)
? ? public @interface MyAnnotations {
? ? ? ? MyAnnotation[] value();
? ? }
? ? @Repeatable(MyAnnotations.class)
? ? @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ElementType.TYPE_PARAMETER})
? ? @Retention(RetentionPolicy.RUNTIME)
? ? public @interface MyAnnotation {
? ? ? ? String value() default "aric";
? ? }
? ? /**
? ? * 重復(fù)注解與類型注解
? ? */
? ? public class TestAnnotation {
? ? ? ? @MyAnnotation("hello")
? ? ? ? @MyAnnotation("test")
? ? ? ? public void show(@MyAnnotation("a") String str){
? ? ? ? ? ? System.out.println(str);
? ? ? ? }
? ? }