<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## [Optional類](https://lingcoder.gitee.io/onjava8/#/book/19-Type-Information?id=optional%e7%b1%bb) 如果你使用內置的`null`來表示沒有對象,每次使用引用的時候就必須測試一下引用是否為`null`,這顯得有點枯燥,而且勢必會產生相當乏味的代碼。問題在于`null`沒什么自己的行為,只會在你想用它執行任何操作的時候產生`NullPointException`。`java.util.Optional`(首次出現是在[函數式編程](https://lingcoder.gitee.io/onjava8/#/docs/book/13-Functional-Programming)這章)為`null`值提供了一個輕量級代理,`Optional`對象可以防止你的代碼直接拋出`NullPointException`。 雖然`Optional`是 Java 8 為了支持流式編程才引入的,但其實它是一個通用的工具。為了證明這點,在本節中,我們會把它用在普通的類中。因為涉及一些運行時檢測,所以把這一小節放在了本章。 實際上,在所有地方都使用`Optional`是沒有意義的,有時候檢查一下是不是`null`也挺好的,或者有時我們可以合理地假設不會出現`null`,甚至有時候檢查`NullPointException`異常也是可以接受的。`Optional`最有用武之地的是在那些“更接近數據”的地方,在問題空間中代表實體的對象上。舉個簡單的例子,很多系統中都有`Person`類型,代碼中有些情況下你可能沒有一個實際的`Person`對象(或者可能有,但是你還沒用關于那個人的所有信息)。這時,在傳統方法下,你會用到一個`null`引用,并且在使用的時候測試它是不是`null`。而現在,我們可以使用`Optional`: ~~~ // typeinfo/Person.java // Using Optional with regular classes import onjava.*; import java.util.*; class Person { public final Optional<String> first; public final Optional<String> last; public final Optional<String> address; // etc. public final Boolean empty; Person(String first, String last, String address) { this.first = Optional.ofNullable(first); this.last = Optional.ofNullable(last); this.address = Optional.ofNullable(address); empty = !this.first.isPresent() && !this.last.isPresent() && !this.address.isPresent(); } Person(String first, String last) { this(first, last, null); } Person(String last) { this(null, last, null); } Person() { this(null, null, null); } @Override public String toString() { if (empty) return "<Empty>"; return (first.orElse("") + " " + last.orElse("") + " " + address.orElse("")).trim(); } public static void main(String[] args) { System.out.println(new Person()); System.out.println(new Person("Smith")); System.out.println(new Person("Bob", "Smith")); System.out.println(new Person("Bob", "Smith", "11 Degree Lane, Frostbite Falls, MN")); } } ~~~ 輸出結果: ~~~ <Empty> Smith Bob Smith Bob Smith 11 Degree Lane, Frostbite Falls, MN ~~~ `Person`的設計有時候又叫“數據傳輸對象(DTO,data-transfer object)”。注意,所有字段都是`public`和`final`的,所以沒有`getter`和`setter`方法。也就是說,`Person`是不可變的,你只能通過構造器給它賦值,之后就只能讀而不能修改它的值(字符串本身就是不可變的,因此你無法修改字符串的內容,也無法給它的字段重新賦值)。如果你想修改一個`Person`,你只能用一個新的`Person`對象來替換它。`empty`字段在對象創建的時候被賦值,用于快速判斷這個`Person`對象是不是空對象。 如果想使用`Person`,就必須使用`Optional`接口才能訪問它的`String`字段,這樣就不會意外觸發`NullPointException`了。 現在假設你已經因你驚人的理念而獲得了一大筆風險投資,現在你要招兵買馬了,但是在虛位以待時,你可以將`Person Optional`對象放在每個`Position`上: ~~~ // typeinfo/Position.java import java.util.*; class EmptyTitleException extends RuntimeException { } class Position { private String title; private Person person; Position(String jobTitle, Person employee) { setTitle(jobTitle); setPerson(employee); } Position(String jobTitle) { this(jobTitle, null); } public String getTitle() { return title; } public void setTitle(String newTitle) { // Throws EmptyTitleException if newTitle is null: title = Optional.ofNullable(newTitle) .orElseThrow(EmptyTitleException::new); } public Person getPerson() { return person; } public void setPerson(Person newPerson) { // Uses empty Person if newPerson is null: person = Optional.ofNullable(newPerson) .orElse(new Person()); } @Override public String toString() { return "Position: " + title + ", Employee: " + person; } public static void main(String[] args) { System.out.println(new Position("CEO")); System.out.println(new Position("Programmer", new Person("Arthur", "Fonzarelli"))); try { new Position(null); } catch (Exception e) { System.out.println("caught " + e); } } } ~~~ 輸出結果: ~~~ Position: CEO, Employee: <Empty> Position: Programmer, Employee: Arthur Fonzarelli caught EmptyTitleException ~~~ 這里使用`Optional`的方式不太一樣。請注意,`title`和`person`都是普通字段,不受`Optional`的保護。但是,修改這些字段的唯一途徑是調用`setTitle()`和`setPerson()`方法,這兩個都借助`Optional`對字段進行了嚴格的限制。 同時,我們想保證`title`字段永遠不會變成`null`值。為此,我們可以自己在`setTitle()`方法里邊檢查參數`newTitle`的值。但其實還有更好的做法,函數式編程一大優勢就是可以讓我們重用經過驗證的功能(即便是個很小的功能),以減少自己手動編寫代碼可能產生的一些小錯誤。所以在這里,我們用`ofNullable()`把`newTitle`轉換一個`Optional`(如果傳入的值為`null`,`ofNullable()`返回的將是`Optional.empty()`)。緊接著我們調用了`orElseThrow()`方法,所以如果`newTitle`的值是`null`,你將會得到一個異常。這里我們并沒有把`title`保存成`Optional`,但通過應用`Optional`的功能,我們仍然如愿以償地對這個字段施加了約束。 `EmptyTitleException`是一個`RuntimeException`,因為它意味著程序存在錯誤。在這個方案里邊,你仍然可能會得到一個異常。但不同的是,在錯誤產生的那一刻(向`setTitle()`傳`null`值時)就會拋出異常,而不是發生在其它時刻,需要你通過調試才能發現問題所在。另外,使用`EmptyTitleException`還有助于定位 BUG。 `Person`字段的限制又不太一樣:如果你把它的值設為`null`,程序會自動把將它賦值成一個空的`Person`對象。先前我們也用過類似的方法把字段轉換成`Optional`,但這里我們是在返回結果的時候使用`orElse(new Person())`插入一個空的`Person`對象替代了`null`。 在`Position`里邊,我們沒有創建一個表示“空”的標志位或者方法,因為`person`字段的`Person`對象為空,就表示這個`Position`是個空缺位置。之后,你可能會發現你必須添加一個顯式的表示“空位”的方法,但是正如 YAGNI\[^2\] (You Aren't Going to Need It,你永遠不需要它)所言,在初稿時“實現盡最大可能的簡單”,直到程序在某些方面要求你為其添加一些額外的特性,而不是假設這是必要的。 請注意,雖然你清楚你使用了`Optional`,可以免受`NullPointerExceptions`的困擾,但是`Staff`類卻對此毫不知情。 ~~~ // typeinfo/Staff.java import java.util.*; public class Staff extends ArrayList<Position> { public void add(String title, Person person) { add(new Position(title, person)); } public void add(String... titles) { for (String title : titles) add(new Position(title)); } public Staff(String... titles) { add(titles); } public Boolean positionAvailable(String title) { for (Position position : this) if (position.getTitle().equals(title) && position.getPerson().empty) return true; return false; } public void fillPosition(String title, Person hire) { for (Position position : this) if (position.getTitle().equals(title) && position.getPerson().empty) { position.setPerson(hire); return; } throw new RuntimeException( "Position " + title + " not available"); } public static void main(String[] args) { Staff staff = new Staff("President", "CTO", "Marketing Manager", "Product Manager", "Project Lead", "Software Engineer", "Software Engineer", "Software Engineer", "Software Engineer", "Test Engineer", "Technical Writer"); staff.fillPosition("President", new Person("Me", "Last", "The Top, Lonely At")); staff.fillPosition("Project Lead", new Person("Janet", "Planner", "The Burbs")); if (staff.positionAvailable("Software Engineer")) staff.fillPosition("Software Engineer", new Person( "Bob", "Coder", "Bright Light City")); System.out.println(staff); } } ~~~ 輸出結果: ~~~ [Position: President, Employee: Me Last The Top, Lonely At, Position: CTO, Employee: <Empty>, Position: Marketing Manager, Employee: <Empty>, Position: Product Manager, Employee: <Empty>, Position: Project Lead, Employee: Janet Planner The Burbs, Position: Software Engineer, Employee: Bob Coder Bright Light City, Position: Software Engineer, Employee: <Empty>, Position: Software Engineer, Employee: <Empty>, Position: Software Engineer, Employee: <Empty>, Position: Test Engineer, Employee: <Empty>, Position: Technical Writer, Employee: <Empty>] ~~~ 注意,在有些地方你可能還是要測試引用是不是`Optional`,這跟檢查是否為`null`沒什么不同。但是在其它地方(例如本例中的`toString()`轉換),你就不必執行額外的測試了,而可以直接假設所有對象都是有效的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看