無IDE下編譯和執行Java的方法

2014-08-05    分類:JAVA開發、程式設計開發、首頁精華0人評論發表於2014-08-05

最近 Java subreddit 出現了一篇”在沒有IDE的情況下編譯Java包” 的帖子,這個帖子丟擲了這麼一個問題,“是否存在一個命令可以編譯一組處於同一資料夾下獨立包內的java檔案的方法(這稱之為bin),同時怎樣執行新的類檔案呢?” 它的提出者 kylolink解釋說,“當我開始依賴Eclipse來編寫程式碼時就開始擔心沒有Eclipse時自己該怎麼寫程式碼了。” 我看過很多次這類問題,事實上,這促使我(目前已經四年了)發了一篇文章: GPS系統和IDE:究竟是好還是壞? 我喜歡強大的現代化的Java的整合開發環境(IDE),因為它使得我的程式設計更加輕鬆,但知道如何構建和執行簡單的Java示例也是有必要的,這篇文章主要就是著重於如何做到這些的。

我部落格中一篇文章 通過簡單的測試學習Java,其中寫了我喜歡用一個簡單的文字編輯器和命令列工具來編寫並且執行簡單的程式。現在我有個很棒的想法,是關於我最喜歡的java ide的,即早期決定使用IDE的好處是為了保證“開銷”。在大多數實際應用程式中,毫無疑問IDE的開銷是值得的。然而,對於最簡單的示例應用程式並非總是如此。這篇文章的剩餘部分展示了在沒有遇到這些情況的前提下是如何構建和執行Java程式碼的。

建立和執行Java程式碼

為了對這篇文章進行更具體的討論,我將使用一些非常簡單的Java類,在同一個包中通過彼此相關的組合或繼承(不在 未命名的包中)來呼叫dustin.examples。這兩個在第三個類之前是沒有 main 函式的,直到 Main.java 才有 main 函式為了在沒有IDE的情況下執行示例。三個類的程式碼清單如下。

Parent.java

package dustin.examples;

public class Parent
{
   @Override
   public String toString()
   {
      return "I'm the Parent.";
   }
}

Child.java

package dustin.examples;

public class Child extends Parent
{
   @Override
   public String toString()
   {
      return "I'm the Child.";
   }
}

Main.java

package dustin.examples;

import static java.lang.System.out;

public class Main
{
   private final Parent parent = new Parent();
   private final Child child = new Child();

   public static void main(final String[] arguments)
   {
      final Main instance = new Main();
      out.println(instance.parent);
      out.println(instance.child);
   }
}

接下來顯示了目錄結構與這些類的 .java 原始檔。截圖顯示原始檔的目錄層次結構代表了包名(dustin/examples 源自包 dustin.examples)和該子目錄下被稱為package-reflecting的目錄層次結構 src。我還建立了 classes 子目錄(當前為空)用於存放編譯後檔案 .class 檔案,因為 javac 在目錄不存在的情況下不會建立該目錄。

用javac構建和執行java

無論使用哪種方法正常地構建Java程式碼(Ant, Maven, Gradle, 或者 IDE),我相信謹慎的做法是,至少了解如何使用 javac來構建Java程式碼。Oracle/Sun的支持者們使用 javac 命令列工具的基本項來執行, javac -help 也可以執行 javac -help -X來檢視其它的擴充套件選項。如何應用這些選項的更多細節可以在 Windows 或者 Unix/Linux的javac的文件工具檢視。

當進入 javac 文件 時, -sourcepath 選項可以被用來表示原始檔存在的路徑。在上面所呈現的目錄結構中,假設我在執行 C:\java\examples\javacAndJava\ 目錄的 javac 命令,這將意味著會需要這樣的命令: javac -sourcepath src src\dustin\examples\*.java。下一張截圖顯示了結果。

因為我們沒有指定 .class 檔案的目標目錄,在預設情況下它們被放置在同一個目錄下被編譯的 .java 原始檔。我們可以使用 -d 選項來糾正這種情況。我們現在可以執行的命令,例如 javac -sourcepath src -d classes src\dustin\examples\*.java。如前所述,指定目標目錄(classes)必須是存在的。這樣,命令將會在下面的截圖指定的目錄下定位.class檔案。

用Java原始檔編譯成適當的 .class 檔案在指定的目錄中,我們現在可以執行Java應用程式啟動命令列工具 java。這僅僅是通過by java -help 所示的指令或者是 java工具頁 和.class 檔案的 -classpath 所指定的地方(或 -cp)選項。使用兩種方法來指定 classes目錄以便用於找到 .class 檔案,接下來的截圖印證了這點。最後一個引數是完全合格的(整個Java包)類名,它有一個 main 函式來執行。下面的截圖顯示了java -cp classes dustin.examples.Main 和java -classpath classes dustin.examples.Main的命令。

構建和執行Ant

對於最簡單的Java應用程式, javac and java 使用起來非常簡單,它們用於構建並執行應用程式就分別證明了這一點。應用程式會稍微複雜一點(如程式碼中存在多個包/目錄或更復雜的依賴於第三方庫和框架的類路徑),但這種方法非常難用。 Apache Ant 是最古老的“三巨頭”,它是被用於成千上萬的應用程式部署的Java構建工具。正如我討論過 以前的一篇部落格,一個基礎的Ant構建檔案很容易被建立,特別是如果都始於一個模板就像我在 這篇文章中介紹的一樣。

接下來的程式碼是Ant的 build.xml 檔案的,它將 .java 檔案 編譯成 .class檔案然後執行 dustin.examples.Main 類就像上面的 javac 和 java一樣。

build.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="BuildingSansIDE" default="run" basedir=".">
   <description>Building Simple Java Applications Without An IDE</description>

   <target name="compile"
           description="Compile the Java code.">
      <javac srcdir="src"
             destdir="classes"
             debug="true"
      includeantruntime="false" />
   </target>

   <target name="run" depends="compile"
           description="Run the Java application.">
      <java classname="dustin.examples.Main" fork="true">
         <classpath>
           <pathelement path="classes"/>
         </classpath>
      </java>
   </target>
</project>

我沒有使用Ant也沒有包括一般所用的方式(例如 “clean” 和 “javadoc”),我使用的是 javac和 java來使例子儘可能的簡單。請注意我使用了”debug”來給javac Ant 任務設定”true”;因為這不是Ant的預設方式而是javac的預設方式。的確,Ant的 javac task 和 java task與 javac and java的命令工具非常相似。

因為我希望使用預設名稱Ant來構建檔案的時候不顯式指定(build.xml),因為我提供“執行”的目標,構建檔案的“預設形式”,因為“編譯”作為一個依賴包括“執行”的目標,此外Ant是我的環境路徑,我所需要做的是在命令列上讓Ant來編譯執行目錄下的“ant”型別的 build.xml檔案示例,下圖就印證了這一點。

雖然我演示了用Ant編譯和執行一個簡單的Java應用程式,通常我只用Ant進行編譯同時用java來執行(或者如果classpath非常複雜時就使用 java指令碼來執行)。

用Maven來搭建和執行

雖然Ant是第一個主流的Java構建工具, Apache Maven 最終獲得了成功在很大程度上要感謝它採用的配置是按照慣例同時也支援常見的庫。當程式碼和生成的 標準目錄佈局物件一致時,Maven很容易使用。很遺憾,我的例子不遵循這個目錄結構,但Maven允許我 覆蓋預設的目錄結構。下面的Maven POM檔案覆蓋了原始碼和目標目錄以及提供了一個Maven構建所需的最小元素,此時Maven的版本是Maven 3.2.1。

pom.xml

<project>
   <modelVersion>4.0.0</modelVersion>
   <groupId>dustin.examples</groupId>
   <artifactId>CompilingAndRunningWithoutIDE</artifactId>
   <version>1</version>

   <build>
      <defaultGoal>compile</defaultGoal>
      <sourceDirectory>src</sourceDirectory>
      <outputDirectory>classes</outputDirectory>
      <finalName>${project.artifactId}-${project.version}</finalName>
   </build>
</project>

因為上面的 pom.xml 檔案指定了一個“compile”的“defaultGoal”, pom.xml 是預設定義的POM檔案,用執行器(mvn)來搜尋,因為Maven安裝的 bin 資料夾在我的path環境變數中,我只需要執行“mvn”來編譯 .class 檔案,這在下張截圖中將會顯示。

我也可以用Maven的 mvn exec:java -Dexec.mainClass=dustin.examples.Main命令來執行編譯後的應用程式,下圖得以展示。

與Ant一樣,我通常不使用Maven執行簡單的Java應用程式,而是用 java 執行編譯後的程式碼(或者使用指令碼直接呼叫 java 的classpath路徑)。

用Gradle構建和執行

Gradle 是最新,最流行和最時尚的三大主流Java構建工具之一。我有時會懷疑時髦東西的本質,但是我發現了有不少東西 例如Gradle (用Groovy編寫的XML, 內建Ant支援和Ivy支援,配置按照慣例很容易被覆蓋,Maven儲存庫支援等)。下一個例子顯示了一個Gradle構建檔案,它可用於編譯和執行一個簡單的應用程式,這裡主要展示一下示例程式碼。它改編自我在部落格 簡單Gradle Java外掛定義的例子。

build.gradle

apply plugin: 'java'
apply plugin: 'application'

// Redefine where Gradle should expect Java source files (*.java)
sourceSets {
    main {
        java {
            srcDirs 'src'
        }
    }
}

// Redefine where .class files are written
sourceSets.main.output.classesDir = file("classes")

// Specify main class to be executed
mainClassName = "dustin.examples.Main"

defaultTasks 'compileJava', 'run'

前兩行 build.gradle 檔案指定 Java plugin 和 Application plugin的應用程式,它將許多功能自動構建。“sourceSets” 和 “sourceSets.main.output.classesDir”的定義允許覆蓋Gradle’s Java 外掛各自的Java原始碼和編譯檔案類的預設目錄。“mainClassName”明確了規範類應該作為應用程式的一部分外掛執行。“defaultTasks”指定要執行的任務,只需在命令列鍵入:‘compileJava’是一個標準的提供任務的Java外掛,‘run’是一個標準的提供任務的應用程式的外掛。因為我稱構建檔案為 build.gradle ,因為我指定預設的‘compileJava’任務和‘run’ 方式,因為我有Gradle的 bin資料夾安裝目錄,我需要做的就是構建和執行示例來 鍵入“gradle”命令,接下來將得到證實。

甚至最大的懷疑者都承認Gradle構建對於這個簡單示例都非常方便。它的某些約定和假設結合了簡潔的依賴,很容易根據需要重寫選擇違約的機制。這一事實,這在Groovy而不是XML中也非常吸引人!

Ant和Maven一樣,我傾向於只用這些工具,通過 java 或者指令碼呼叫 java來直接構建和執行編譯好的 .class檔案。順便說一下,我通常也儲存這些 .class 檔案為JAR來執行,但這超出了本文的範圍。

總結

IDE通常沒有必要構建簡單的應用程式和例子,它的開銷甚至比最簡單的例子都要多,這時直接使用 javac 和 java 來構建和執行例項就顯得非常方便。為了使Ant,Maven或者Gradle的構建工具變得更加有吸引力,許多IDE支援著這些構件工具,這意味著開發者要將構件工具轉移到IDE上,如果已經確定了先前建立的過程,那麼IDE支援的簡單應用就已經成長為了一個成熟的專案。

來自:ImportNews

相關文章