新聞中心
每種?編程語言都提供了表達(dá)我們的想法并將其轉(zhuǎn)化為現(xiàn)實的方法。

創(chuàng)新互聯(lián)主要從事網(wǎng)站制作、成都網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)伍家崗,十多年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
有些是該特定語言所獨有的,有些是許多其他編程語言所共有的。
在本文中,我將探討開發(fā)人員在日常編程工作中經(jīng)常使用的十個 Java 編程特性。
集合的工廠方法
集合是我們?nèi)粘>幋a中最常用的功能。它們被用作我們存儲對象并傳遞它們的容器。
集合還用于對對象進行排序、搜索和迭代,使程序員的生活更輕松。它提供了一些基本的接口,如List、Set、Map等,以及多種實現(xiàn)。
傳統(tǒng)的創(chuàng)建方式對許多開發(fā)人員Collections來說Maps可能看起來很冗長。
這就是為什么 Java 9 引入了一些非常簡潔的工廠方法。
List:
List countries = List.of("Bangladesh", "Canada", "United States", "Tuvalu");
Set:
Set countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");Map:
MapcountriesByPopulation = Map.of("Bangladesh", 164_689_383, "Canada", 37_742_154, "United States", 331_002_651, "Tuvalu", 11_792);
當(dāng)我們想要創(chuàng)建不可變?nèi)萜鲿r,這些非常方便。但是,如果我們要創(chuàng)建可變集合,建議使用傳統(tǒng)方法。
如果您想了解有關(guān)集合框架的更多信息,請訪問此處:集合框架。
本地類型推斷
Java 10 引入了對局部變量的類型推斷,這對開發(fā)者來說超級方便。
傳統(tǒng)上,Java 是一種強類型語言,開發(fā)人員在聲明和初始化對象時必須指定兩次類型。似乎很乏味。看下面的例子:
Map> properties = new HashMap<>();
我們在上述聲明中指定了雙方的信息類型。如果我們在一個地方定義它,我們的眼睛很容易解釋這必須是一種Map類型。Java 語言已經(jīng)足夠成熟,Java 編譯器應(yīng)該足夠聰明,可以理解這一點。本地類型推斷正是這樣做的。
上面的代碼現(xiàn)在可以寫成如下:
var properties = new HashMap>();
現(xiàn)在我們必須編寫和鍵入一次。上面的代碼可能看起來并沒有那么糟糕。但是,當(dāng)我們調(diào)用方法并將結(jié)果存儲在變量中時,它會縮短很多。例子:
var properties = getProperties();
相似地,
var countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");盡管這似乎是一個方便的功能,但也有一些批評。一些開發(fā)人員會爭辯說,這可能會降低可讀性,這比這個小便利更重要。
要了解更多信息,請訪問:
打開 JDK Lvti-Faq
打開 JDK Lvti-style-guide
增強的開關(guān)表達(dá)式
傳統(tǒng)的 switch 語句從一開始就在 Java 中,類似于 C 和 C++。沒關(guān)系,但是隨著語言的發(fā)展,它直到 Java 14 才為我們提供任何改進。它當(dāng)然也有一些限制。最臭名昭著的是跌倒:
為了解決這個問題,我們使用了 break 語句,它們幾乎是樣板代碼。但是,Java 14 引入了一種查看此 switch 語句的新方法,并提供了許多更豐富的功能。
我們不再需要添加 break 語句;它解決了跌倒問題。最重要的是,switch 語句可以返回一個值,這意味著我們可以將其用作表達(dá)式并將其分配給變量。
爪哇
int day = 5;String result = switch (day) { case 1, 2, 3, 4, 5 -> "Weekday"; case 6, 7 -> "Weekend"; default -> "Unexpected value: " + day;};閱讀有關(guān)它的更多信息:使用 Switch 表達(dá)式進行分支
記錄
盡管記錄是 Java 中相對較新的功能,在 Java 16 中發(fā)布,但許多開發(fā)人員發(fā)現(xiàn)創(chuàng)建不可變對象非常有用。
我們經(jīng)常需要在我們的程序中使用數(shù)據(jù)職業(yè)對象來保存或?qū)⒅祻囊环N方法傳遞到另一種方法。例如,一個攜帶 x、y 和 z 坐標(biāo)的類,我們將其編寫如下。
package ca.bazlur.playground;import java.util.Objects;public final class Point { private final int x; private final int y; private final int z; public Point(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } public int x() { return x; } public int y() { return y; } public int z() { return z; } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null || obj.getClass() != this.getClass()) return false; var that = (Point) obj; return this.x == that.x && this.y == that.y && this.z == that.z; } @Override public int hashCode() { return Objects.hash(x, y, z); } @Override public String toString() { return "Point[" + "x=" + x + ", " + "y=" + y + ", " + "z=" + z + ']'; }}這門課看起來超級冗長,與我們的整個意圖無關(guān)。整個代碼可以用以下代碼替換 -
package ca.bazlur.playground;public record Point(int x, int y, int z) {}可選的
方法是一種契約:我們在定義它時會考慮到它。我們指定參數(shù)及其類型以及返回類型。當(dāng)我們調(diào)用一個方法時,我們期望它按照約定行事。如果沒有,則違反合同。
但是,我們經(jīng)常從方法中獲取 null 而不是指定類型的值。這是違規(guī)行為。調(diào)用者不能預(yù)先知道,除非它調(diào)用它。為了解決這種違規(guī),調(diào)用程序通常使用 if 條件測試該值,無論該值是否為空。例子:
public class Playground { public static void main(String[] args) { String name = findName(); if (name != null) { System.out.println("Length of the name : " + name.length()); } } public static String findName() { return null; }}看上面的代碼。該findName()方法應(yīng)該返回一個String值,但它返回 null。調(diào)用者現(xiàn)在必須先檢查空值才能處理它。如果調(diào)用忘記這樣做,他們最終會得到NullPointerException不是預(yù)期的行為。
另一方面,如果方法簽名指定了不能返回值的可能性,它將解決所有的混亂。這就是Optional發(fā)揮作用的地方。
import java.util.Optional;public class Playground { public static void main(String[] args) { Optional optionalName = findName(); optionalName.ifPresent(name -> { System.out.println("Length of the name : " + name.length()); }); } public static Optional findName() { return Optional.empty(); }} 現(xiàn)在我們findName()用 Optional 重寫了方法,它指定了不返回任何值的可能性,我們可以處理它。這會向程序員發(fā)出預(yù)先警告并修復(fù)違規(guī)行為。
Java 日期時間 API
每個開發(fā)人員都在某種程度上對日期時間計算感到困惑。這不是夸大其詞。這主要是由于長期以來沒有一個好的 Java API 來處理 Java 中的日期和時間。
然而,這個問題不再存在,因為 Java 8 在java.time包中帶來了一套出色的 API,可以解決所有與日期和時間相關(guān)的問題。
java.time包提供了許多接口和類來解決處理日期和時間的大多數(shù)問題,包括時區(qū)(有時會非常復(fù)雜)。但是,我們主要使用以下類 -
- 本地日期
- 當(dāng)?shù)貢r間
- 本地日期時間
- 期間
- 時期
- ZonedDateTime 等
這些類旨在具有通常需要的所有方法。例如
import java.time.LocalDate;import java.time.Month;public class Playground3 { public static void main(String[] args) { LocalDate date = LocalDate.of(2022, Month.APRIL, 4); System.out.println("year = " + date.getYear()); System.out.println("month = " + date.getMonth()); System.out.println("DayOfMonth = " + date.getDayOfMonth()); System.out.println("DayOfWeek = " + date.getDayOfWeek()); System.out.println("isLeapYear = " + date.isLeapYear()); }}同樣,LocalTime 具有計算時間所需的所有方法。
LocalTime time = LocalTime.of(20, 30);int hour = time.getHour(); int minute = time.getMinute(); time = time.withSecond(6); time = time.plusMinutes(3);
我們可以將它們結(jié)合起來-
LocalDateTime dateTime1 = LocalDateTime.of(2022, Month.APRIL, 4, 20, 30);LocalDateTime dateTime2 = LocalDateTime.of(date, time);
我們?nèi)绾伟〞r區(qū)-
ZoneId zone = ZoneId.of("Canada/Eastern");LocalDate localDate = LocalDate.of(2022, Month.APRIL, 4);ZonedDateTime zonedDateTime = date.atStartOfDay(zone);有用的 NullPointerException
每個開發(fā)人員都討厭空指針異常。當(dāng) StackTrace 不提供有用的信息時,它變得具有挑戰(zhàn)性。為了演示這個問題,讓我們看一個例子:
package com.bazlur;public class Main { public static void main(String[] args) { User user = null; getLengthOfUsersName(user); } public static void getLengthOfUsersName(User user) { System.out.println("Length of first name: " + user.getName().getFirstName()); }}class User { private Name name; private String email; public User(Name name, String email) { this.name = name; this.email = email; } //getter //setter}class Name { private String firstName; private String lastName; public Name(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } //getter //setter}看上面代碼的main方法。我們可以看到我們會得到一個空指針異常。如果我們使用 pre-Java 14 運行和編譯代碼,我們將獲得以下 StackTrace:
Exception in thread "main" java.lang.NullPointerExceptionat com.bazlur.Main.getLengthOfUsersName(Main.java:11)at com.bazlur.Main.main(Main.java:7)
這個堆棧跟蹤是可以的,但是它沒有太多關(guān)于這個 NullPointerException 發(fā)生在哪里以及為什么發(fā)生的信息。
但是,在 Java 14 及更高版本中,我們可以在堆棧跟蹤中獲得更多信息,這非常方便。在 Java 14 中,我們將獲得:
殼
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "ca.bazlur.playground.User.getName()" because "user" is nullat ca.bazlur.playground.Main.getLengthOfUsersName(Main.java:12)at ca.bazlur.playground.Main.main(Main.java:8)
可完成的未來
我們逐行編寫程序,通常它們會逐行執(zhí)行。但是,有時我們希望相對并行執(zhí)行以使程序更快。為此,我們通常參考 Java 線程。
好吧,Java 線程編程并不總是與并行編程有關(guān)。相反,它為我們提供了一種組合程序的多個獨立單元以獨立執(zhí)行以與其他單元一起取得進展的方法,并且它們通常是異步運行的。
然而,線程編程及其復(fù)雜性似乎很可怕。大多數(shù)初級和中級開發(fā)人員都在為此苦苦掙扎。這就是為什么 Java 8 帶來了一個更直接的 API,讓我們可以完成程序的一部分異步運行。讓我們看一個例子:
假設(shè)我們必須調(diào)用三個 REST API,然后組合結(jié)果。我們可以一一稱呼。如果它們每個都需要大約 200 毫秒,那么獲取所有它們的總時間將需要 600 毫秒。
如果我們可以并行運行它們會怎樣?由于現(xiàn)代 CPU 中包含多核,因此它們可以輕松處理三個不同 CPU 上的三個休息調(diào)用。使用 CompletableFuture,我們可以輕松實現(xiàn)這一點。
爪哇
package ca.bazlur.playground;import java.time.Duration;import java.time.Instant;import java.util.List;import java.util.concurrent.CompletableFuture;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;public class SocialMediaService { public static void main(String[] args) throws ExecutionException, InterruptedException { var service = new SocialMediaService(); var start = Instant.now(); var posts = service.fetchAllPost().get(); var duration = Duration.between(start, Instant.now()); System.out.println("Total time taken: " + duration.toMillis()); } public CompletableFuture> fetchAllPost() { var facebook = CompletableFuture.supplyAsync(this::fetchPostFromFacebook); var linkedIn = CompletableFuture.supplyAsync(this::fetchPostFromLinkedIn); var twitter = CompletableFuture.supplyAsync(this::fetchPostFromTwitter); var futures = List.of(facebook, linkedIn, twitter); return CompletableFuture.allOf(futures.toArray(futures.toArray(new CompletableFuture[0]))) .thenApply(future -> futures.stream() .map(CompletableFuture::join) .toList()); } private String fetchPostFromTwitter() { sleep(200); return "Twitter"; } private String fetchPostFromLinkedIn() { sleep(200); return "LinkedIn"; } private String fetchPostFromFacebook() { sleep(200); return "Facebook"; } private void sleep(int millis) { try { TimeUnit.MILLISECONDS.sleep(millis); } catch (InterruptedException e) { throw new RuntimeException(e); } }}
閱讀更多關(guān)于它的信息。
Lambda 表達(dá)式
Lambda 表達(dá)式可能是 Java 語言中最強大的功能。它重塑了我們編寫代碼的方式。Lambda 表達(dá)式就像一個匿名函數(shù),可以接受參數(shù)并返回一個值。
我們可以將函數(shù)分配給一個變量,并將它作為參數(shù)傳遞給一個方法,一個方法可以返回它。它有一個身體。與方法的唯一區(qū)別是它沒有名稱。
表達(dá)簡短而簡潔。它通常不包含太多樣板代碼。讓我們看一個例子:
我們想列出擴展名為 .java 的目錄中的所有文件。
爪哇
var directory = new File("./src/main/java/ca/bazlur/playground");String[] list = directory.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".java"); }});如果您仔細(xì)查看這段代碼,我們將匿名內(nèi)部類傳遞給方法list()。在內(nèi)部類中,我們放置了過濾掉文件的邏輯。
本質(zhì)上,我們對這段邏輯感興趣,而不是圍繞邏輯的樣板。
事實上,lambda 表達(dá)式允許我們刪除所有樣板,我們可以編寫我們關(guān)心的代碼。例子:
var directory = new File("./src/main/java/ca/bazlur/playground");String[] list = directory.list((dir, name) -> name.endsWith(“.java"));好吧,我只是在這里向您展示了一個示例,但是 lambda 表達(dá)式還有很多其他好處。
流 API
“Lambda 表達(dá)式是通向 Java 8 的入門藥物,但 Streams 才是真正的癮?!? 文卡特·蘇布拉馬尼亞姆。
在我們的日常編程工作中,我們經(jīng)常做的一項常見任務(wù)是處理一組數(shù)據(jù)。有一些常見的操作,例如過濾、轉(zhuǎn)換和收集結(jié)果。
在 Java 8 之前,這類操作本質(zhì)上是必不可少的。我們必須為我們的意圖(也就是我們想要實現(xiàn)的目標(biāo))以及我們想要的方式編寫代碼。
隨著 Lambda 表達(dá)式和流 API 的發(fā)明,我們現(xiàn)在可以以聲明方式編寫數(shù)據(jù)處理功能。我們只指定我們的意圖,但我們不必寫下我們?nèi)绾蔚玫浇Y(jié)果。讓我們看一個例子:
我們有一個書籍列表,我們希望找到所有 Java 書籍的名稱,這些名稱以逗號分隔和排序。
public static String getJavaBooks(Listbooks) { return books.stream() .filter(book -> Objects.equals(book.language(), "Java")) .sorted(Comparator.comparing(Book::price)) .map(Book::name) .collect(Collectors.joining(", "));}
上面的代碼簡單、易讀、簡潔。替代的命令式代碼是-
public static String getJavaBooksImperatively(Listbooks) { var filteredBook = new ArrayList (); for (Book book : books) { if (Objects.equals(book.language(), "Java")){ filteredBook.add(book); } } filteredBook.sort(new Comparator () { @Override public int compare(Book o1, Book o2) { return Integer.compare(o1.price(), o2.price()); } }); var joiner = new StringJoiner(","); for (Book book : filteredBook) { joiner.add(book.name()); } return joiner.toString();}
雖然這兩種方法返回相同的值,但我們清楚地看到了區(qū)別。
網(wǎng)頁題目:十大Java語言特性
文章轉(zhuǎn)載:http://m.5511xx.com/article/dhjside.html


咨詢
建站咨詢
