Java 9概览
對(duì)于許多Java 9來說,它似乎是一個(gè)維護(hù)版本,它推動(dòng)了不能在Java 8中實(shí)現(xiàn)的項(xiàng)目Jigsaw。但是,隨著JDK中的新模塊系統(tǒng)以及與之相關(guān)的許多內(nèi)部更改,Java 9也帶來了開發(fā)人員工具箱中一些很棒的新內(nèi)容。 以下是重點(diǎn)內(nèi)容:
- JShell – Java現(xiàn)在具有內(nèi)置的外殼;
- 新的流程API –提供了許多功能來處理以前版本中默認(rèn)缺少的功能;
- 將G1用作默認(rèn)的垃圾收集器–在Java 8中,這是并行GC;
- 全新的HTTP / 2客戶端-由jdk.incubator.httpclient.HttpClient類和jdk.incubator.httpclient包的類提供;
- 新的堆棧遍歷API –提供了用于分析和使用Java堆棧跟蹤的標(biāo)準(zhǔn)API;
- 新的反應(yīng)式編程API –在JDK java.util.concurrent.Flow類中提供了一種標(biāo)準(zhǔn)機(jī)制;
- 語言增強(qiáng)功能–這些是一些較小的語言改進(jìn),最重要的是在接口中具有私有方法的能力(例如,供Java 8中默認(rèn)使用的方法使用)。 對(duì)于Java 10,已經(jīng)提出了將var關(guān)鍵字引入該語言的早期建議(盡管最初計(jì)劃是針對(duì)9)。 Coin項(xiàng)目將帶來進(jìn)一步的改進(jìn)(包括一系列小的語言更改);
- 雜項(xiàng)–改進(jìn)的Javadoc,集合工廠方法(如Set.of(…),Map.of(…),List.of(…)),流API改進(jìn),私有接口方法,多發(fā)行版JAR和許多其他(包括并發(fā)性和安全性增強(qiáng))(本文并不涉及)(好奇的讀者可以在此處查看與Java 9相關(guān)的JEP: http : //openjdk.java.net/projects/jdk9/ )。
在JDK 9中沒有實(shí)現(xiàn)的另一件事是打包了JMH工具,并提供了供應(yīng)用程序使用的默認(rèn)JMH微基準(zhǔn)-那里的工作仍在進(jìn)行中……
打破整體
讓我們考慮一下,我們有一個(gè)Java 9之前的應(yīng)用程序,可以將文本導(dǎo)出為不同的格式-文本,pdf或word。 應(yīng)用程序結(jié)構(gòu)如下:
exporter.IExporter接口為不同的出口商提供了公共接口:
public interface IExporter {public void export(String text, ByteArrayOutputStream baos); }以下是三個(gè)具體的導(dǎo)出器實(shí)現(xiàn):
public class PdfExporter implements IExporter {public void export(String text, ByteArrayOutputStream baos) {Document document = null;try {document = new Document();PdfWriter.getInstance(document, baos);document.open();document.add(new Paragraph(text));document.close();} catch (DocumentException e) {if (document != null) {document.close();}}} }public class WordExporter implements IExporter {public void export(String text, ByteArrayOutputStream baos) {XWPFDocument document = null;try {document = new XWPFDocument();XWPFParagraph paragraph = document.createParagraph();XWPFRun run = paragraph.createRun();run.setText(text);document.write(baos);} catch (IOException e) {try {if (document != null) {document.close();}} catch (IOException e1) {}// some logging or proper error handling ...}} }public class TextExporter implements IExporter {public void export(String text, ByteArrayOutputStream baos) {try {baos.write(text.getBytes());} catch (IOException e) {// some logging or proper error handling ...}} }exporter.Main類是應(yīng)用程序的入口點(diǎn),如果可能具有以下實(shí)現(xiàn),則僅使用PdfExporter類:
public static void main(String[] args) throws IOException {PdfExporter exporter = new PdfExporter();ByteArrayOutputStream baos = new ByteArrayOutputStream();exporter.export("sample text", baos);FileOutputStream fos = new FileOutputStream("example.pdf");fos.write(baos.toByteArray());fos.close(); }對(duì)于PDF和Word導(dǎo)出器,我們需要以下依賴項(xiàng)(我們正在使用Maven構(gòu)建應(yīng)用程序):
<dependencies><dependency><groupid>org.apache.poi</groupid><artifactid>poi</artifactid><version>3.16</version></dependency><dependency><groupid>org.apache.poi</groupid><artifactid>poi-ooxml</artifactid><version>3.16</version></dependency><dependency><groupid>com.lowagie</groupid><artifactid>itext</artifactid><version>2.1.7</version></dependency> </dependencies>因此,第一件事就是為您的應(yīng)用程序定義模塊以及您將要使用的JDK模塊。 您的初始應(yīng)用程序在類路徑上具有所有JDK類,但是您可以將Java 9中的類僅限制為所需的JDK模塊。 對(duì)于我們的簡(jiǎn)單應(yīng)用程序,我們僅使用JDK中的java.io類,它們是每個(gè)Java應(yīng)用程序所需的java.base模塊的一部分。 我們的簡(jiǎn)單應(yīng)用程序不需要其他JDK模塊,因此我們可以為我們的應(yīng)用程序使用非常簡(jiǎn)約的JRE版本。
對(duì)于實(shí)際應(yīng)用,我們可以輕松地得出四個(gè)邏輯模塊:
- 出口商 –此模塊為所有出口商提供通用API(exporter.IExporter類);
- exporter.word –此模塊提供Word導(dǎo)出程序;
- exporter.pdf –此模塊提供PDF導(dǎo)出器;
- exporter.text –此模塊提供文本導(dǎo)出器;
- exporter.demo –此模塊包含Main類,并提供我們應(yīng)用程序的入口點(diǎn)。
接下來的事情是為我們定義的每個(gè)模塊添加模塊元數(shù)據(jù)。 為此,我們?yōu)槊總€(gè)模塊定義一個(gè)module-info.java文件,如下所示:
每個(gè)模塊的模塊元數(shù)據(jù)具有以下內(nèi)容(請(qǐng)注意三個(gè)具體的導(dǎo)出器如何依賴于API模塊,并且由于隱式需要而我們不需要java.base模塊):
module exporter {exports exporter; }module exporter.pdf {requires exporter;requires itext;exports exporter.pdf; }module exporter.text {requires exporter;exports exporter.text; }module exporter.word {requires exporter; }module exporter.demo {requires exporter;requires poi.ooxml;requires poi.ooxml.schemas;exports exporter.word; }我們?nèi)匀恍枰阅撤N方式引用模塊中的第三方庫(kù)(IText和Apache POI)。 如果這些庫(kù)是模塊化版本,我們可以簡(jiǎn)單地下載它們并在相應(yīng)的應(yīng)用程序模塊中需要它們。 但是,我們無法做出此假設(shè),因此我們需要一種“按原樣”將其稱為依賴項(xiàng)的方法。 為了進(jìn)行遷移,Java平臺(tái)提供了一種將第三方庫(kù)用作Java模塊的機(jī)制。 如果這些位于我們應(yīng)用程序的類路徑中,它們將包含在全局“未命名”模塊中,并且?guī)熘械乃泄差悓?duì)我們的應(yīng)用程序模塊都是可見的。 另一方面,為模塊化應(yīng)用程序引入了新的模塊路徑,該路徑指定了所有應(yīng)用程序模塊,也可以使用JAR文件的名稱(不帶.jar擴(kuò)展名)從模塊路徑中引用第三方庫(kù)-這些即所謂的自動(dòng)模塊。 我們希望第二種選擇是更“模塊化”的遷移方法。 現(xiàn)在,最后一件事是構(gòu)建并運(yùn)行我們的模塊化應(yīng)用程序。 實(shí)際上,我們對(duì)模塊結(jié)構(gòu)有不同的策略:例如同一項(xiàng)目中的多個(gè)模塊(我們擁有一個(gè)模塊),每個(gè)項(xiàng)目一個(gè)模塊甚至是嵌套的模塊結(jié)構(gòu)。 同樣,我們可以將module-info.java文件放置在模塊中所需的任何位置,只要在javac編譯過程中指定了此位置(因此位于模塊目錄的根目錄中)。
在撰寫本文時(shí),Maven仍不支持模塊化應(yīng)用程序的構(gòu)建,并且Java IDE(例如Eclipse,IntelliJ和NetBeans)對(duì)Jigsaw模塊具有部分和實(shí)驗(yàn)性的支持。 因此,我們將演示如何從命令行構(gòu)建模塊化的應(yīng)用程序。 為此,我們將首先在原始項(xiàng)目根目錄中創(chuàng)建modules目錄。 并按以下方式構(gòu)建這五個(gè)模塊中的每個(gè)模塊(請(qǐng)注意,Java 9還為javac提供了–module-source-path參數(shù),以便可以立即編譯模塊,但我們將不會(huì)出于演示如何構(gòu)建模塊的目的而使用分別)–我們需要位于項(xiàng)目的根目錄中,并在PATH上擁有最新的JDK 9 bin目錄:
mkdir modules\exporter modules\exporter.pdf modules\exporter.word modules\exporter.text modules\exporter.demo javac -d modules\exporter src\exporter\module-info.java src\exporter\IExporter.java javac --module-path modules -d modules\exporter.text src\exporter\text\module-info.java src\exporter\text\TextExporter.java javac --module-path modules;C:\Users\Martin\.m2\repository\com\lowagie\itext\2.1.7 -d modules\exporter.pdf src\exporter\pdf\module-info.java src\exporter\pdf\PdfExporter.java javac -cp C:\Users\Martin\.m2\repository\org\apache\poi\poi\3.16\poi-3.16.jar --module-path modules;C:\Users\Martin\.m2\repository\org\apache\poi\poi-ooxml\3.16;C:\Users\Martin\.m2\repository\org\apache\poi\poi-ooxml-schemas\3.16 -d modules\exporter.word src\exporter\word\module-info.java src\exporter\word\WordExporter.java javac --module-path modules -d modules\exporter.demo src\exporter\demo\module-info.java src\exporter\demo\Main.java這里有兩個(gè)要點(diǎn)。 首先,請(qǐng)確保從第三方依賴項(xiàng)的Maven目錄中排除了源jar(如果有的話),因?yàn)檫@可能會(huì)使編譯器誤以為您在同一目錄中有重復(fù)的模塊jar(例如poi-3.16和poi-3.16-sources)。罐)。 其次,對(duì)于自動(dòng)模塊,您可能具有從不同庫(kù)導(dǎo)出的相同包(也稱為拆分包 ),這在Java 9中是不允許的。ApachePOI就是這種情況: exporter.word模塊需要poi和poi-ooxml庫(kù)導(dǎo)出org.apache.poi軟件包,如果這兩個(gè)軟件包均作為自動(dòng)模塊包含在內(nèi),則會(huì)導(dǎo)致編譯錯(cuò)誤。 為了在我們的情況下解決此問題,我們?cè)陬惵窂缴习?strong>poi庫(kù),該庫(kù)構(gòu)成所謂的全局未命名模塊,該模塊在自動(dòng)模塊中可見。 現(xiàn)在,為了運(yùn)行演示應(yīng)用程序,您需要運(yùn)行以下命令,將上面用于編譯的模塊路徑/類路徑組合在一起,并指向Main類作為應(yīng)用程序的主要入口點(diǎn):
javac --module-path modules -d modules\exporter.demo src\exporter\demo\module-info.java src\exporter\demo\Main.java因此,您應(yīng)該在當(dāng)前目錄中生成example.pdf文件。
玩Java Shell
JSHell REPL位于JDK9的bin目錄中,您可以通過導(dǎo)航到該目錄并鍵入jshell來簡(jiǎn)單地運(yùn)行它。 您可以(重新)定義和檢查變量,導(dǎo)入,方法和類型。 您還可以保存當(dāng)前進(jìn)度并將其重新加載到JSHell中。 對(duì)于導(dǎo)入,類型和方法,還提供了出色的自動(dòng)補(bǔ)全支持。 為了說明JSHell的基礎(chǔ)知識(shí),請(qǐng)考慮在JShell中嘗試以下命令集:
2 + 3 public int sum(int a, int b) { return a + b; } import java.util.logging import java.util.logging.* Logger x = null; class z {} /help /imports /vars /methods /env /types /list /list -all /save script.jsh /open script.jsh /exit控制外部流程
在Java 9之前,您可以使用兩種方法來創(chuàng)建新進(jìn)程-使用Runtime.getRuntime()。exec()方法或java.lang.ProcessBuilder類,如下所示:
Process p = Runtime.getRuntime().exec("cmd /c notepad"); ProcessBuilder pb = new ProcessBuilder("cmd", "/c", “notepad"); Process p = pb.start();</pre>但是,就管理已創(chuàng)建的進(jìn)程或檢查主機(jī)操作系統(tǒng)中的其他外部進(jìn)程而言,這是非常有限的。 因此,JDK 9一方面為java.lang.Process類引入了許多新方法,另一方面為java.lang.ProcessHandle提供了新的實(shí)用程序,該實(shí)用程序允許以類似流的方式操作外部流程。 以下是新流程API的一些自描述示例:
LOGGER.info("PID: " + process.pid());LOGGER.info("Number of children: " + process.children().count());LOGGER.info("Number of descendants: " + process.descendants().count());ProcessHandle.Info info = process.info();LOGGER.info("Process command: " + info.command());LOGGER.info("Info: " + info.toString());// ProcessHandle handle = process.toHandle();CompletableFuture<process> exitedFuture = process.onExit();exitedFuture.whenComplete((p, e) -> { LOGGER.info("Process exited ... ");});exitedFuture.get();</process></pre> <pre class="brush: java;">ProcessHandle[] processes = ProcessHandle.allProcesses().filter((pHandle) -> { return pHandle.info().toString().contains(name); }).toArray(ProcessHandle[] :: new);for(ProcessHandle process : processes) {LOGGER.info("Process details: " + process.info().toString());}return processes;使用G1提升性能
G1垃圾收集器不是新增功能,而是在JDK 7中引入的。G1的特定之處在于,它按堆中的每個(gè)區(qū)域工作,而不是按代工作,這是清理垃圾的更細(xì)粒度的方法。 它的目的是在尊重一系列約束的同時(shí),清理盡可能多的垃圾。 它是一種低暫停時(shí)間的收集器,可以在低暫停時(shí)間的情況下權(quán)衡高吞吐量。 在JDK 9中,它成為默認(rèn)的垃圾回收器,取代了并行GC(即吞吐量更高的GC)。 此更改背后的假設(shè)是,由較低的GC暫停時(shí)間導(dǎo)致的用戶體驗(yàn)改善要比收集器的高吞吐量更好(并行GC就是這種情況)。 該假設(shè)是否成立還需要應(yīng)用程序來決定–如果有人不愿意冒險(xiǎn)使用G1,仍然可以使用-XX:-UseParallelGC為JVM指定并行GC。
為HTTP 2.0做好準(zhǔn)備
jdk.incubator.http.HttpClient類提供了一個(gè)新的HTTP 2.0客戶端,該客戶端仍處于孵化階段(這意味著可能會(huì)進(jìn)行更多更改)。
走棧軌跡
java.lang.StackWalker類提供了新的堆棧跟蹤檢查API。 它可用于使用類似流的操作以細(xì)粒度方式過濾和處理堆棧跟蹤信息。
包含反應(yīng)式編程
想要提供適合于反應(yīng)式編程范例的發(fā)布-訂閱機(jī)制的應(yīng)用程序必須提供java.util.concurrent.Flow類的實(shí)現(xiàn)。 由JDK提供的一種實(shí)現(xiàn)Flow.Publisher接口的標(biāo)準(zhǔn)發(fā)布者,由java.util.concurrent.SubmissionPublisher類提供。
翻譯自: https://www.javacodegeeks.com/2018/01/java-9-glance.html
總結(jié)
- 上一篇: activemq优先级_ActiveMQ
- 下一篇: java 权威指南_Java 8:Com