Getting Started with Java
Java Overview with Relocatable JDK 8
PREREQUISITES — You should already…
- have experience in some other programming language;
- know how to use the command line (Command Prompt, PowerShell or a POSIX shell).
Introducing the Java Platform
Java™ has been around for centuries; or so it feels to some of us. From its public release in 1995, it has grown to be the most popular programming language in use, as per the TIOBE index (for several years running, no less). For some, it has become the new COBOL, arguably in no small part due to IBM®’s involvement with Java, its many donations, and the Java Platform’s consequent adoption in many financial institutions and multi-national enterprises.
Java is less popular on POSIX-like operating systems like Linux and flavours of Unix, but the popular Android™ operating system’s Linux-based kernel does sport a Java-like API, much to the chagrin of Sun® (bought out), and subsequently Oracle®, who unsuccessfully sued Google®.
Java is an umbrella term for “the world of Java-related languages, technologies and frameworks”, as you may witness on the Java Platform Standard Edition 8 Documentation page. To describe it as HUGE is an understatement; quite a burden to bear for such a tiny name, which for many people used to be slang for “good coffee from a small Indonesian island” .
Platforming
Ubiquitous references to “Java Platform” suggest that, from a developer’s perspective at least, Java is not just a language, but a whole infrastructure of related technologies. For all intents and purposes then: an operating system. A virtual operating system, using a virtual CPU called the Java Virtual Machine (JVM).
Virtual Machinery
Java code is translated to virtual machine code instructions (also called “bytecode”), following the JVM (Java Virtual Machine) specifications. This is equivalent to the .NET Framework’s IL (Intermediate Language). Other languages, other than Java, also target the JVM — noteably Scala and the hot new favourite: Kotlin, courtesy of Mother Russia.
The VM bytecode is translated on the fly to the native machine code of the host computer, using JIT compilation☆
(Just-In-Time compilation) techniques. Although the start-up might be a tad tardy, Java programs run quite fast.
All things being equal, this means that a compiled Java program will run on any platform supported by a Java Virtual Machine. At minimum, the Java Runtime Environment (JRE) is required — the Java Development Kit (JDK) part is necessary to compile Java, package programs, and create documentation.
☆
Java programs can be compiled ahead of time, to reduce the start-up costs.
Garbage Collection Time
Java is a garbage-collected language, which means programmers only allocate memory; they are never required to release the memory. The automatic reclamation of memory is called “garbage collection”, and is based on maintaining a count of references to allocated objects; when the reference count is 0
, the garbage collection process will reclaim that memory for reuse.
It can be get a bit more complicated than that, depending on what your program does, but generally, it “just works”, and memory leaks are the least of your concerns.
Write Once Run Anywhere… Well, Mostly, If You Try Hard
This is a very common Java refrain, and mostly valid for web development, as long as you use an Oracle-certified application server, or you write JavaFX hybrid programs. For real-world applications, it depends entirely on the kind of application. In practice it turns out that, if you are careful, you can write most code, so that it mostly runs on most JVMs (with the right version, of course).
Most substantial Java programs, even Netbeans, have to “drop down” to the host operating system on occasion. Interfacing with native code is possible, and almost mandatory for certain types of applications.
Almost all programs supply some native executable “launcher” to better integrate with the operating system, but none are official, except of course, for java
and javaw
, which are not exactly “user friendly”.
Frameworks Galore
Sounds better than “a superlative mind-numbing collection of libraries, not even taking third-party contributions into consideration”. To help unravel this veritable heap, the libraries are collected in related categories, or frameworks.
Compact Profile
For Java on embedded systems, or small devices, a set of classes without GUI frameworks is available. This is enough to write typical applications not involving graphics or enterprise features. It even includes scripting and JDBC database classes.
Java SE
For larger applications, but not enterprise applications, the Java SE (Standard Edition) API adds GUI classes, with Swing arguably the most popular.
JRE Classes
This is the set of classes available by default when the Java runtime is installed on client machines. It is a superset of the Java SE classes, because it includes Java Web Start, Applets (deprecated in Java 9), and JavaFX.
JDK Classes
Apart from the Java EE (Enterprise Edition) classes, this is the biggest set, because it must not only include all the above, but also add development-related classes and tools.
Java Language Features
We will not attempt to cover even a fraction of the whole Java Platform, since our focus, at least here, is the Java programming language part of this massive ecosystem. Application of a programming language requires tools, structure, conventions and applications — all of which we will address, but without any IDEs (Integrated Development Environments) to blur the details.
General Features
Much of the Java syntax borrows from C++; it was designed to be easy for C++ programmers to learn Java, not because its syntax is ground-breaking or elegant. Many parts of the Java language will appear familiar to C++ programmers; some parts may look familiar even to C, C#, JavaScript, Perl and PHP programmers, because they all borrowed some features from C.
Blocks
Braces are ubiquitous — delimiters for the venerable block structure, in lieu of begin
and end
keywords from other programming language branches. Blocks can be compound statements, function body blocks, class blocks, amongst other manifestations. We can rightly say that Java is a “block-structured language”.
Every block introduces a new scope — an area of visibility with respect to some user-defined identifier. Since blocks can nest, scopes can nest. Identifiers defined in an outer block, are visible in nested blocks, but can be hidden by re-defining the same name.
Source Code
Source code files can be (and in our opinion, should be) UTF-8 encoded, even though that is not the default encoding anywhere☆
in Java. This means you should add the -encoding utf8
option to the Java compiler (javac
options).
The language is case-sensitive, and free format. As a result, whitespace (spaces, tabs, newlines, carriage returns, form feeds) serves no syntactical purpose, other than to separate tokens which otherwise would have been ambiguous. The burden is on the programmer to ensure readable code, and to consistently indent nested blocks.
☆
Not even the javadoc
tool defaults to UTF-8 encoding in the HTML it generates. It too requires explicit switches: -encoding utf8 -docencoding utf8 -charset utf8
!
Statically Typed
Types must be known at compile time. No Java syntax allows for static type inference along the lines of auto
in C++, or var
in C#, so redundant type names in declarative statements are still de rigueur.
Java is a strongly typed language, which has nothing to do with the force required to press keys. Java has specific rules regarding implicit and explicit type conversions (type casts) with a cast operator. Object-oriented implicit narrowing (up casts) to a base class (super class), and interfaces are supported.
Reflection is supported in Java via the java.lang.reflect
API, which allows for dynamic loading for libraries, or even dynamic resolving of methods at runtime. But the language is, in spirit, still a statically typed language.
Native Code Interfaces
It is possible, though rather convoluted, to interface with native C/C++ libraries using the Java Native Interface (JNI). One unfortunate step in the process, is to create wrapper C/C++ code, even when calling API functions in the operating system libraries.
A newer, and highly recommended option, is Java Native Access (JNA), which does not require you to write interface code. This means you can call, for example, Windows Kernel32.dll API functions without writing C/C++ code.
Properties & Overloaded Operators
Neither are supported in Java, just in case you come from a C# or C++ background. In Java ye shall write yer “getters and setters” (like C++), and call functions to perform arithmetic on your custom types. Operators, after all, are basically compact notations for calling functions, most commonly, built-in functions. Function or operator: both are “called”, both take arguments (operands), both return results; the difference is notation. You lose out on notation only, not ability.
Abstraction Mechanisms
From this point, Java establishes itself as a modern object-oriented language, running on a virtual machine (JVM), supplied with a huge framework of packages and tools.
Defiantly Object-Oriented
Java is unashamedly object-oriented; even proudly “doing the Right Thing™”. Apart from comments, and some directives, everything must be inside a class
structure (block). For simpler programs, which do not require OOP features, several static
functions can be created in the same class, in which case the class acts more like a module. You may even have several such “modules” in the same application (not to be confused with the modules introduced in Java 9).
Like C#, Java does not support multiple inheritance in line with C++, but they both can implement multiple interfaces, which are special classes with no fields (data members). An object of a class that implements several interfaces, can be implicitly cast to any interface.
One can happily use all modern object-oriented features in Java: encapsulation, inheritance, interface inheritance, and polymorphism via virtual functions (oops: methods). By the way, we will use the term “function” when we discuss the syntax and behaviour, and “method” when we emphasise the object-oriented aspects.
Generic Generics
Java was relatively late to the generics party, but this has been available since 2004, so it has seen some use. Abstractly, this involves creating template classes, from which types can be instantiated, replacing parts of the template with specifics. Methods can also be written as “generics” functions.
So, a List<String>
is a type instantiated “on the fly”, so to speak, from the generic List<?>
interface type. This, however, is just an abstraction — Java, unlike C++, does not really physically copy source code and replace parts of it.
NOTE — Generic is Not What it Used to Be
The term “generic”, as used in languages that have some form of template-based programming paradigm, has no relevance to how the term has been applied in the past. We used to talk about “generic code” and “generic functions” as good coding practice to write widely-applicable, and reusable code, within the framework of any language, including C. Today, you have to be cognisant of the context in which the word is used; particularly in C#, C++ and Java, all of which have generics. Thus writing a “generic function” may have a different meaning, depending on the topic at hand.
Template-based programming is historically a mechanism to enhance performance in statically typed languages, where the alternative would be constantly converting types.
Fashionably Functional
In line with a common trend, Java also supports some aspects of functional programming, mostly by virtue of lambda expressions (anonymous functions), and the ability to return or pass methods. But functions are not “first class citizens” (a moronic term, if ever there was one), or “function objects” in Java.
Framework/Package/Namespace/Directory Scaffolds
One might argue that part of Java’s success is due to its enormous API, which many of a certain persuasion may appreciate. Java Platform, Enterprise Edition (Java EE) adds even more libraries for fault-tolerant, multi-tier software running on an application server, i.e. web applications.
The Java language itself provides syntax and structure, but has no built-in functions. It does have a number of primitive types, which are not really object-oriented, but they can be “wrapped” in corresponding classes. Learning Java implies also learning several core classes, or basically, most of the Java Platform Standard Edition (SE) classes. Some classes are application-specific, and which to learn depends on your needs.
Libraries are packaged; Java’s equivalent of namespaces, which manifests as nested directory structures — which you may forget only at your peril.
Build Tools & Launchers
Because of Java’s intricate use of class path lookups, and the preponderance of nested directory structures for packages, many Java-specific build tools are available. Arguably the three most popular are: Apache Ant (with Apache Ivy), Apache Maven, and Gradle (based on Groovy, and used to build Android™).
Unless you have no choice, or really like XML, or only use an IDE, we suggest you use Gradle; it has the smallest learning curve, does not use XML, and is concise. Maven, however, is probably more common in open-source projects. Of course, nothing prevents you from using a traditional Make tool, like GNU Make.
The closest a Java program gets to being an executable, is by packing it with the jar
tool in a structured Zip file with a .jar
extension. Even then, invoking the Java runtime to execute your Java program can involve complicated class path incantations, especially for larger programs with many library dependencies. Most programs provide some sort of “wrapper” script or program to “launch” such Java .jar
files more conveniently. One open-source option is Launch4j, which can wrap your application as a light-weight .exe
.
Get Your Java On
Once you have some high-level perspective on the exhilarating Java experience awaiting you, it is time to get yourself a Java Software Development Kit (JDK) for your platform.
JDK SE on Windows
The obvious and official method is to download the Java SE Development Kit 8 and install it. For Windows, you can choose the 32-bit, or 64-bit, JDK. After installation, you can find the location of the JDK with the following Command Prompt command:
for %F in (javac.exe) do @echo. %~$PATH:F
In Windows 10, you can also try: ‘where javac
’.
The base directory (e.g. C:\Program Files\Java\jdk1.8.0_152
) can be copied anywhere, since that is the complete JDK. You can even uninstall the JDK afterwards, set your JAVA_HOME
and PATH
environment variables to where you copied the JDK, and you are good to go.
Alternatively, you have several options, including jdkPortable, but it is mostly for use by other portable applications. You might use it to download and install (copy, really) the JDK SE for you, which by default will go into a ‹base›\CommonFiles\JDK64
directory. This directory, again, contains the complete JDK.
If you want to do it the hard way, check out these instructions on Stack Overflow. This basically involves extracting the JDK installer .exe
with 7-Zip, finding the tools.zip
file inside, which you extract somewhere, and then running a Command Prompt command in that directory, to convert .pack
files to .jar
files:
for /r %F in (*.pack) do .\bin\unpack200 -r "%F" "%~dF%~pF%~nF.jar"
The process is similar for JDK 9, if you feel so inclined, except the tools.zip
is easier to find, and there are fewer files to unpack. It is significantly bigger though.
If you place the following batch file in the JDK base directory, it will set the JAVA_HOME
and PATH
environment variables automatically. It is designed to be called from within a current Command Prompt session, or more likely, from the accompanying rxjdk-cmd.cmd
batch file.
rxjdk-env.cmd
— Relocatable JDK Environment
@echo off & setlocal enableextensions
:: Set PATH for Java JDK and utilities. It only sets the environment.
:: Use `rxjdk-cmd.cmd` to open a new Command Prompt, with the settings
:: from this file. Can be run in an existing Command Prompt session.
::
:: LICENCE: MIT — https://opensource.org/licenses/MIT
endlocal
:: If `rxJDK_BASE` already exists, simply terminate, otherwise we will
:: keep on prefixing (potentially) the same directory to `PATH`.
if defined rxJDK_BASE goto EXIT
:: Get this batch file's directory, and strip trailing backslash.
set rxJDK_BASE=%~dp0
set rxJDK_BASE=%rxJDK_BASE:~0,-1%
:: Prefix to current `PATH` environment variable.
set PATH=%rxJDK_BASE%\bin;%rxJDK_BASE%\jre\bin;%PATH%
:: Set `JAVA_HOME`s. You can add more settings here.
set "JAVA_HOME=%rxJDK_BASE%"
set "JAVA8_HOME=%rxJDK_BASE%"
set "JRE_HOME=%rxJDK_BASE%\jre"
set "JDK_HOME=%rxJDK_BASE%"
set "JDK8_HOME=%rxJDK_BASE%"
:: Change the prompt to remind us that we're in the relocatable JDK
:: environment.
set PROMPT=[rxJDK8] $p$_$g$s
:EXIT
endlocal
This batch file, also to be placed in the base JDK directory, will call the above rxjdk-env.cmd
batch file to set the environment, and then launch a new Command Prompt window with these settings. Doing this allows the batch file to set the title of the new Command Prompt window to rxJDK8
, and change the prompt without affecting an existing session, and it can be double-clicked from a File Manager.
The other advantage is that any settings you make to the Console will persist in the Windows Registry using the title of the Console window. We suggest you set your font to Consolas
for good Unicode (UTF-8) coverage. If you are not using Windows 10 with recent updates, you should change the PROMPT
setting, and everywhere else we use ESC
up to the next m
.
rxjdk-cmd.cmd
— Relocatable JDK Command Prompt
@echo off & setlocal enableextensions
:: Opens new Command Prompt window with a portable Java JDK 8 (64-bit)
:: environment, with `PATH` set, so that `java`, `javac`, etc. can be
:: run from the command line, from any directory. If not on Windows 10,
:: change the `PROMPT` setting below to your liking.
::
:: LICENCE: MIT — https://opensource.org/licenses/MIT
setlocal enabledelayedexpansion
:: The following batch file only sets the environment and PATH.
call rxjdk-env.cmd
:: Open a new command prompt window, with appropriate title.
set ESC=
set MSG= Portable JDK Environment
set PROMPT=$e[36;40;7m$srxJDK8$s$e[0m $e[33;1m$p$e[0m$_$g$s$e[0m
start "rxJDK8" /D %rxJDK_BASE%\..\ cmd.exe /K ^
echo.^&echo %ESC%[38;5;220m%MSG%%ESC%[0m ^&^
%rxJDK_BASE%\startup.cmd
goto :EXIT
:EXIT
endlocal
Important — Hard-Coded ESC
The
ESC
variable is followed by a hard-coded ASCII escape character (code27
), but it will not display in HTML. It will copy though, otherwise just enter it yourself, assuming you know how to do that in your editor.
For easy customisation, the above rxjdk-cmd.cmd
batch loads a startup.cmd
file, where you can add further customisation. An example is shown below, but you can modify it to your liking, maybe even change the working directory to your workspace. The chcp…
command sets UTF-8 encoding for the Command Prompt, so you probably want to leave that as is.
startup.cmd
— Relocatable JDK Customised Startup
@echo off & setlocal enableextensions
:: custom startup loaded from `rxjdk-cmd.cmd`.
::
doskey aliases=doskey /macros
doskey alias=doskey $*
doskey jc=javac -Xlint -Xdiags:verbose -encoding utf8 $*
doskey ja=java %rxJRE_OPTS% $*
doskey jw=javaw %rxJRE_OPTS% $*
doskey jv=cvtjava $*
doskey jd=javadoc -encoding utf8 -docencoding utf8 -charset utf8 $*
doskey ls=dir /b $*
doskey rm=del $*
doskey which=for %%F in ($1) do @echo.%%~$PATH:F
chcp 65001 2>&1 >nul
:EXIT
endlocal
The doskey
command is useful to create aliases for often-used commands. You can check the location of any executable (but you must specify the full name) with the which
alias. It searches in directories listed in the PATH
environment variable, and you can thus check if it finds the correct executable. Otherwise, try Windows 10’s ‘where
‹executable›’ command.
Now all you need is an editor, and you can effectively write any Java SE program you like. Other tools simply make certain processes easier as programs get bigger, but to learn Java, this is all you need. And you can always add more tools later.
JDK SE On Linux & MacOS
On Linux and MacOS, you may want to try SDKMAN!, which can download and manage a JDK for you. It can also download and manage other Java-related tools and environments. Alternatively, you can install the official versions, or use your package manager.
Ubuntu and Debian
On Ubuntu-based systems and Debian, you can use the webupd8.org PPA repository. The commands are as follows, assuming you have already updated your system:
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
You will be requested to confirm your acceptance of Oracle’s binary licence agreement before the installation will continue. An oracle-java9-installer
package is also available, if you lean that way. Just for safety, you can install the following package, which will set your new JDK 8 as the default:
sudo apt install oracle-java8-set-default
Generally, this should not be necessary on Ubuntu, since it is installed by default, but it will not hurt if you run the above command. You can verify that javac
is on your PATH
with:
javac -version
Now you have a working Java Platform 8 Software Development Kit. If you want, you can investigate jEnv, but that is only necessary if you are going to run different versions of the JDK.
MacOS Sierra & High Sierra
If you are on MacOS and not already using Homebrew, you are doing yourself a disservice. Homebrew can also be used to install a Java JDK. By default, it installs the latest available, via Casks which you enable in Homebrew as follows:
brew tap caskroom/cask
brew update
To enable brew cask
to install a JDK other than the latest version, run this command:
brew tap caskroom/versions
brew cask search "java*"
The search
will now show java8
as an option. You can install that JDK 8 with:
brew cask install java8
Java’s SDKs are installed on MacOS under /Library/Java/JavaVirtualMachines
, and you may have several versions installed without a problem. Just set your JAVA_HOME
to the appropriate directory, e.g.:
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk‹version›.jdk/Contents/Home
If you only use one version, you can put that in your .bash_profile
or .bashrc
file. To see which versions are installed, you can run:
/usr/libexec/java_home -V
You could also manage your different JDK versions with jEnv, which you can install via Homebrew with:
brew install jenv
You can check StackOverflow for more ideas, and you can run the following command to get the Java view of your environment, under any operating system:
java -XshowSettings:properties -version
Minimal Test Program
Once you have a working JDK on your PATH
, you can test it out by writing a minimal program. Here we will painstakingly describe the process to create a new (simple) Java program. This process will suffice until we graduate to larger programs containing several classes and files.
Program Directory
As good practice would dictate, the first step is to create a directory for your program. For simple programs this may seem overkill, but it is better to be consistent. Following tradition, we shall create a HelloWorld
directory, in an arbitrary location, e.g. C:\Course
, or $HOME/Course
(POSIX), and make it the current directory.
Windows:
mkdir C:\Course 2>&1 >nul & cd C:\Course
mkdir HelloWorld & cd HelloWorld
The redirection of output to the NUL:
device is to (hopefully) suppress error messages if the directory already exists. Even if it does display a message (one cannot always redirect all Microsoft’s commands’ output), it should not be of any concern, just untidy.
POSIX:
mkdir $HOME/Course 2>&1 >/dev/null; cd $HOME/Course
mkdir HelloWorld; cd HelloWorld
To save on typing, you can use tilde (~
) as alias for $HOME
in interactive POSIX shells.
Create / Edit Source Code
Using any editor, though we use gvim
(or vim
if you want) in the example command lines below, we must create a Java source file, with the .java
extension. The name of the file is important — it must exactly match the public
class name in the file, so we must think ahead.
gvim Hello.java
In this Hello.java
source file, we can now enter the following, then save it. The @file
and @brief
parts represent our documentation convention; you do not have to do that in real Java code.
Hello.java
— Minimal Java Test Example Console Program
/*!@file Hello.java
* @brief Minimal Hello World in Java
* Compile with: `javac -Xlint -Xdiags:verbose -encoding utf8 Hello.java`
*/
public class Hello { //←match filename!
public static void main (String[] args) { //←must have this.
String who = "World"; //←set default.
if (args.length > 0) //←check arguments.
who = args[0]; //←replace default.
System.out.println("Hello, " + who + "!"); //←output greeting.
System.exit(0); //←good convention.
}
}//class
Note that our code formatting style differs from popular styles in two major ways:
We do not indent code inside a class. Indenting wastes a lot of space, since most code is inside classes, resulting in the majority of code in a file being indented, which adds little benefit.
We indent our closing curly brace, which keeps the visual impact cleaner.
You are welcome to use your own style, and may even be required to adhere to a particular style by your employers or customers. Whatever style you prefer, just ensure it is consistent, and critically considered (”liking” a style is an emotion, not a reason).
Compilation & Execution
Once saved, the source code must be compiled. This is done with the javac
tool. Always. Regardless of IDE, or any other environment. That button you click in the IDE, just runs javac
for you.
javac -Xlint -Xdiags:verbose -encoding utf8 Hello.java
If there are no errors, the result will be a Hello.class
file in the same directory. You could have added a ‘-d
‹directory›’ option to place the result in another location, if you wanted.
Since the Hello.class
file is not a native executable, we need the JRE java
tool (or javaw
) to orchestrate the class loading, bytecode JITing, and final execution:
java Hello
java Hello "Jacqui Coosner"
- You must not append the
.class
extension. - Arguments to the program are passed after the
Hello
class name. - Arguments containing spaces must be quoted (that is a requirement of your shell).
If your program contained Javadoc-formatted documentation comments (which our example does not), you could generate the API documentation in HTML format to some ‹dir›
ectory:
javadoc -encoding utf8 -docencoding utf8 -charset utf8 -d ‹dir› Hello.java
We shall revisit Javadoc documentation in the Template
example below.
Basic Java
Once you can create .java
source files in a project directory, you have to consider the basic structure of source files, and which keywords to avoid in names (identifiers) you create. You can refer to the Java Quick Reference and Glossary page at any time, but here we represent the main starting points.
Keywords and Reserved Words
Java has a number of keywords which cannot be used for purposes other than intended. In addition, the language specifies a number of reserved words, which have no purpose (yet), but should not be used for user-defined identifiers.
Syntax — Java Key/Reserved Words
abstract
assert
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
enum
extends
false
final
finally
float
for
goto
if
implements
import
instanceof
int
interface
long
native
new
null
package
private
protected
public
return
short
static
strictfp
super
switch
synchronized
this
throw
throws
transient
true
try
void
volatile
while
Note that technically, null
, true
and false
are literals, while const
and goto
are reserved; so is a single underscore (_
) character (since Java 9).
Java 9 adds a few more contextual, or restricted keywords, which are only keywords in certain places in the structure of a program. You should treat them as keywords anyway in new programs, even Java 8 programs, to ensure a smooth eventual migration to JDK 9.
Syntax — Java 9 Restricted Keywords
exports
module
open
opens
provides
requires
to
uses
transitive
with
Primitive Types and Wrappers
Primitive types are not class types. Variables of a primitive types to the actual primitive value, and not a reference to the object, which is the case for all other types.
Syntax — Primitive Types
char
boolean
byte
short
int
long
float
double
Wrapper classes for the primitive types allow one to box a primitive type as a class type, which means it can be nullable.
Syntax Primitive Wrapper Types
Character
Boolean
Byte
Short
Integer
Long
Float
Double
Structure & Organisation
If you are new to Java, do not sweat the details here… this is about a structural pattern you can reuse; not about syntax. Without all the comments and useful constants, the structure is simple:
Pattern — Simple Java Console Applications
‹importsopt›
public class
‹main-class›{
public static void main (String[]
args
) {
‹statementsopt›
}
‹fieldsopt›
‹methodsopt›
‹constructorsopt›
‹static-initialiseropt›
}
- ‹imports› namespace directives to avoid fully-qualified names.
- ‹main-class› at most one
public
class per file.- ‹statements› program flow and behaviour.
- ‹fields› either
static
(shared) or “instance” variables (data members) at class level.- ‹methods› either
static
(shared) or “instance” member functions.- ‹static-initialiser› may initialise only
static
‹fields›.
As you can see, most of the members are optional. The only requirement is main
, and the fact that the ‹main-class› must be in a file called: ‹main-class›.java
. Because of the fact that the file name and class name must match, only one public
class per .java
file is allowed. Where you put the curly braces is a style, Java does not care — we just tend to use traditional styling in formal syntax and patterns.
In single-class programs, or generally in the class that contains main
, we have no ‹constructors›, and only static
‹fields› and static
‹methods›; and sometimes, a <static initialiser›. More advanced, is the ability to create nested classes.
The order of the members is not important — arrange the members as you feel is easiest to read and understand; just be consistent.
Practical Learning Java Template
To get closer to real-world Java programming, but still keep control, we present here a structure for creating simple Java programs, which will scale to larger programs — until you start using IDEs or build tools to manage your projects.
Workspace and Projects
Although the terms workspace, solution and project are often seen in IDEs, these are not formal Java concepts — just practical terms. For our purposes, the Java workspace is C:\Course\work
on Windows, or $HOME/Course/work
on POSIX-like systems, but you can choose any location you like. Every new program, or project, will get a subdirectory under the workspace directory.
Inside a project directory, you should have a src
(source) directory, a doc
(documentation) directory, and a bin
(binaries) directory. Once you start using packages (this is a Java “thing”), the src
and bin
directories will have further subdirectories that reflect the package naming.
The first step is to choose a name for your project; let us say: Template
. Assuming your chosen workspace directory exists, and that it is the current working directory, the following commands will create the project directory and subdirectories:
mkdir Template
cd Template
mkdir src
mkdir bin
You can create the doc
directory as well, but the javadoc
tool will create it automatically once we start using it.
Build Scripts
We could use one of the several build tools available, but initially they would just add complexity, and will not help you understand a Java program’s infrastructure. To make it easy for you to control and understand the build process, we present two build scripts: build.cmd
for Windows, and build
for POSIX-like shells.
NOTE — Java Archive Executables
Once programs grow beyond a few classes, and you start using third-party libraries, you should package your application in an executable .jar
file; otherwise it becomes what we call “a royal mess”. Although this is not necessary for small programs such as the Template
here, the scripts do create .jar
files. You execute .jar
files with the normal java
program, adding the -jar
switch: ‘java
‹jre-options› -jar
‹jar-file› ‹prg-args›’.
These build scripts also create “launcher” shell scripts (a batch file on Windows) to run your Java program from the .jar
file. They are also created in the ./bin
directory, and should always stay in the same directory as the corresponding .jar
file.
build.cmd
— Windows Java Build Script
@echo off & setlocal enableextensions
::
:: Windows Command Prompt batch file template to build Java projects.
:: Set your main class in `JC_MAIN`. Uncomment the `javadoc` line, if
:: you also want the script to create your Javadoc documentation.
::
:: Add or remove `javac` options to/from `JC_OPTS`. For `javadoc`, do
:: the same for `JD_OPTS`.
::
setlocal
set JC_MAIN=Template
set JC_OPTS=-Xlint -Xdiags:verbose -encoding utf8 -cp . -d ..\bin
set JD_OPTS=-encoding utf8 -docencoding utf8 -charset utf8
pushd .\src
javac %JC_OPTS% %JC_MAIN%.java
if "%ERRORLEVEL%" neq "0" (
popd
goto EXIT
)
:: Create an executable `.jar` file (with automatic manifest).
cd ..\bin
jar cvfe %JC_MAIN%.jar %JC_MAIN% *.class
:: Create Javadoc documentation. Un/comment the next line as needed.
cd ..\src
javadoc %JD_OPTS% -d ..\doc *.java
popd
:: Create a simple “launcher” batch file for the project. You can set
:: the values of `JRE_OPTS` as you see fit, from the examples here.
if not EXIST bin\%JC_MAIN%.cmd (
echo @echo off ^& setlocal enableextensions > bin\%JC_MAIN%.cmd
echo set JRE_OPTS=-Duser.country=ZA -Duser.language=en_ZA ^
>> bin\%JC_MAIN%.cmd
echo set JRE_OPTS=%%JRE_OPTS%% -Duser.timezone=Africa/Johannesburg ^
>> bin\%JC_MAIN%.cmd
echo set JRE_OPTS=%%JRE_OPTS%% -cp %%~dp0;. ^
>> bin\%JC_MAIN%.cmd
echo java %%JRE_OPTS%% -jar %%~dp0%JC_MAIN%.jar %%* ^
>> bin\%JC_MAIN%.cmd
)
:EXIT
endlocal
Place a copy of this batch file in your project directory. If you are satisfied with the options set, you only have to modify the JC_MAIN
value, and set it to the name of the class file containing main
(without the .java
extension), for every new project. You run the script simply by executing: build
on the command line. The equivalent script for POSIX shells (bash), is shown below:
build
— POSIX Shell Java Build Script
#!/usr/bin/env bash
#
# Bash shell script file template to build Java projects. Set your
# main class in `JC_MAIN`. Uncomment the `javadoc` line, if you also
# want the script to create your Javadoc documentation.
#
# Add or remove `javac` options to/from `JC_OPTS`. For `javadoc`, do
# the same for `JD_OPTS`.
#
JC_MAIN=Template
JC_OPTS="-Xlint -Xdiags:verbose -encoding utf8 -cp . -d ../bin"
JD_OPTS="-encoding utf8 -docencoding utf8 -charset utf8"
pushd ./src > /dev/null
javac ${JC_OPTS} ${JC_MAIN}.java
EXITCODE=$?
if [[ $EXITCODE != 0 ]]; then
popd > /dev/null
exit $EXITCODE
fi
# Create an executable `.jar` file (with automatic manifest)
cd ../bin
jar cvfe ${JC_MAIN}.jar ${JC_MAIN} *.class
# Create Javadoc documentation. Un/comment the next line as necessary.
cd ../src
javadoc ${JD_OPTS} -d ../doc *.java
popd > /dev/null
# Create a simple “launcher” batch file for the project. You can set
# the values of `JRE_OPTS` as you see fit, from the examples here.
if [ ! -f bin/$JC_MAIN ]; then
touch bin/$JC_MAIN; chmod a+x bin/$JC_MAIN
echo '#/usr/bin/env bash' > bin/$JC_MAIN
echo 'DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"' \
>> bin/$JC_MAIN
echo 'JRE_OPTS="-Duser.country=ZA -Duser.language=en_ZA"' \
>> bin/$JC_MAIN
echo 'JRE_OPTS="$JRE_OPTS -Duser.timezone=Africa/Johannesburg"' \
>> bin/$JC_MAIN
echo 'JRE_OPTS="$JRE_OPTS -cp ${DIR}:."' \
>> bin/$JC_MAIN
echo "java \${JRE_OPTS} -jar \${DIR}/$JC_MAIN.jar \"\$@\"" \
>> bin/$JC_MAIN
fi
For your convenience, you should run: chmod a+x build
on this script, so you can execute it simply with: ./build
.
Template.java
— Java Template for Console Applications
/** Template class for simple console applications.
* <p>
* This can provide the structure for other console applications. The
* static constructor sets the encoding of output to
* <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> on all
* systems. This will also work for Windows™, as long as you have set
* the codepage: <code>chcp 65001</code> in your Command Prompt — Java
* provides no standard way to do that, and we do not want to get
* involved with JNI/JNA at this stage. UTF-8 is the default in most
* POSIX-like shells.</p>
*/
import static java.lang.System.out;
public class Template {
// EVERY JAVA PROGRAM IS REQUIRED TO HAVE A PUBLIC STATIC MAIN FUNCTION
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
/** Startup prints useful information.
* <p>
* This program does not do much, except for printing out some useful
* system information, that is often needed in real programs. It will
* write out any arguments passed to the program.</p>
* <p>
* If you are running in a terminal, or have managed to set the Windows
* Console to interpret ANSI/VT100 escape sequences, you can clear the
* screen (for example) with:
* <code>System.out.print("\033[2J\033[0;0H");</code></p>
*
* More at <a href="https://en.wikipedia.org/wiki/ANSI_escape_code"
* >WikiPedia - ANSI escape code</a>.
*
* @param args Arguments are written out, if any were passed.
*/
public static void main (String[] args) {
out.print("\n ENVIRONMENT INFO ");
for (int i = 0; i < 50; ++i) out.print('-');
String w = "\n %-15s: %s";
final String OS = osNAME + " - " + osVER;
out.format(w, "OS Platform", OS );
out.format(w, "User Home", userHOME);
out.format(w, "Work Directory", appCWD );
out.format(w, "Application Dir", appDIR );
out.format(w, "Java Runtime", javaHOME);
if (args.length > 0)
for (int i = 0; i < args.length; ++i)
out.format("\n Argument #%02d : %s", i+1, args[i]);
out.println();
System.exit(0);
}
// STATIC FIELDS AND CONSTANTS (FINALS) THAT ARE INITIALISED AT STARTUP
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
/** Application's current working directory at startup. */
public final static String appCWD = System.getProperty("user.dir");
/** User home directory; works correctly in JRE 8. */
public final static String userHOME = System.getProperty("user.home");
/** JRE location; can be overridden with <code>JAVA_HOME</code>." */
public final static String javaHOME = System.getProperty("java.home");
/** Operating system name, as the JRE sees it. */
public final static String osNAME = System.getProperty("os.name");
/** Operating system version, as the JRE sees it. */
public final static String osVER = System.getProperty("os.version");
/** Will be <code>true</code> if running on Windows™. */
public final static boolean isWINOS = osNAME.startsWith("Windows");
/** Will be <code>true</code> if not running on Windows™. */
public final static boolean isPOSIX = !isWINOS;
/** Location of the <strong>application</strong> directory. */
public static String appDIR = null; //←set below.
// OPTIONAL STATIC CONSTRUCTOR USED HERE TO INITIALISE THE APPLICATION
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static {
try {
appDIR = new java.io.File(
Template.class.getProtectionDomain()
. getCodeSource().getLocation().toURI().getPath()
).toString();//←get executable path.
if (appDIR.endsWith(".jar"))
appDIR = appDIR.substring(
0, appDIR.lastIndexOf(java.io.File.separatorChar));
System.setOut(
new java.io.PrintStream(
new java.io.FileOutputStream(java.io.FileDescriptor.out),
true, "UTF-8")
);//←set UTF-8 encoding on `out`.
}
catch (Exception ex) {
// optional:
// throw new ExceptionInInitializerError(ex);
}
}
}//class
Once you have saved the file in ‹workspace›/Template/src
, and assuming Template
is your working directory where you saved the build scripts, you can compile the program on Windows by simply running build
, and in POSIX shells, with: ./build
. You can execute the program on Windows with: bin\Template
, and POSIX with: bin/Template
. In either case, you can pass the program arguments, enclosing arguments that contain spaces in double quotes. Here is an example run on Ubuntu Linux 16.04:
bin/Template ABC "DEF GHI"
ENVIRONMENT INFO --------------------------------------------------
OS Platform : Linux - 4.4.0-104-generic
User Home : /home/brx
Work Directory : /home/brx/Work/java/Template
Application Dir: /home/brx/Work/java/Template/bin
Java Runtime : /usr/lib/jvm/java-8-oracle/jre
Argument #01 : ABC
Argument #02 : DEF GHI
And on Windows 10 (unfortunately, Java does not provide the build version number, which would have been very useful):
bin\Template ABC "DEF GHI"
ENVIRONMENT INFO --------------------------------------------------
OS Platform : Windows 10 - 10.0
User Home : C:\Users\brx
Work Directory : D:\Work\proj\java\Template
Application Dir: D:\Work\proj\java\Template\bin
Java Runtime : D:\Work\rxjdk8u152\jre
Argument #01 : ABC
Argument #02 : DEF GHI
We could not resist adding Javadoc documentation, since you really should do that as soon as possible, even if it is not complex or verbose.
Note that it is generally not a good idea to use static
constructors, but it will suffice until we have enough knowledge to consider other options.
Java Archive Executables Summary
This is just a summary of how to create simple executable .jar
files, in case you want to roll your own build scripts.
cd bin
jar cvfe Template.jar Template *.class
cd ..
java -jar bin/Template ABC "DEF GHI"
The last line executes the Template
class from the Template.jar
file. The .jar
file can be any name; it did not have to be Template.jar
; but it is important that you provide the start class name (the one containing main
), which in this case, is Template
.
Incus Data Java Launcher
It is very frustrating that the Windows 10 Console supports VT100/ANSI escape sequences, but none of java.exe
, python.exe
or perl.exe
command-line programs enable that mode in the Console. Nor do the Windows Console developers allow one a setting to enable Virtual Terminal mode in the Console settings, nor an environment variable, nor a Registry setting. The Command Prompt enables it for itself, but the moment you run console programs, Command Prompt reverts the setting first (and re-enables it again when the program exits).
This means that, unless a program performs some non-portable low-level calls to SetConsoleCP
and SetConsoleMode
in the Windows API, you cannot write even rudimentary portable programs that use terminal escape sequences — unless you use a third-party library, or manually use JNI/JNA for Java. This is really tedious and quite unacceptable.
For java.exe
then, we wrote a C replacement, called cvtjava.exe
, which sets the 65001
code page (Windows Console UTF-8), and enables the Console Virtual Terminal mode. It can be called just like java.exe
, except that it will show the following screen when called with no arguments, or with a --help
switch. All the output colour is effected only with ANSI escape sequences — even clearing the screen is now portable.
Using the Virtual Terminal Java Launcher
The output of cvtjava --help
should explain it, but we will reiterate the information here. We stress that all work is performed by Oracle’s java.exe
; cvtjava.exe
is only a “wrapper” for it. It does not depend on any particular version of Java, as long as you have an original java.exe
on your PATH
, whether it is the standard JRE one, or a JDK one.
As Replacement for java.exe
You must ensure that cvtjave.exe
is on your PATH
. We always have C:\bin
first in our PATH
, for utilities exactly like this. Everywhere you are instructed to run java
, you can then just run cvtjava
, which will call java.exe
. Any arguments are simply passed to java.exe
.
You can go one step further, by copying or renaming cvtjava.exe
to java.exe
. The only caveat is that you must make sure it will be found first (must be in a directory listed before the original java.exe
in your PATH
environment variable). Our java.exe
will find the official one, call it, and pass all arguments to it. This makes it a 100% replacement — except you will have UTF-8 and Virtual Terminal processing enabled, for all .jar
or .class
programs executed.
As Executable Jar File Launcher
Assume you have an executable Jar file, e.g., Template.jar
. You can then make a copy of our cvtjava.exe
to the same directory as the .jar
file: Template.exe
. When named this way, our launcher will see that there is a .jar
file with the same name, and instruct java.exe
to execute the file (with a ‘--jar
‹jarfile›’ argument).
JRE Settings in Environment Variable
Any JRE settings you want to automatically pass to the original java.exe
, you can place in an environment variable called: rxJRE_OPTS
. This will automatically be expanded as first argument(s) to java.exe
. The arguments are not validated in any way, and if the syntax is incorrect, the error messages will come from java.exe
, not our launcher.
UTF-8 and Fonts
The Console will handle UTF-8 fine, but your font may not have the appropriate glyphs. Unless you have some other preference that works for you, we suggest you use Consolas
. The launcher could set that automatically, but that might frustrate users who like their own fonts. Maybe later we can add an option to do that, maybe with an .ini
file, which could then also set the colour template. In the meantime, you can use our conpal.exe
program to set the palette to one of seven (0
…7
) schemes, the default (0
) being the new Windows 10 Console colour scheme.
Java Test Program
If you want to test the cvtjava.exe
launcher, you can replace the main
function in Template.java
with the following version:
public static void main (String[] args) {
out.print("\033[2J\033[0;0H");
out.print("\n\033[32;1;7m ENVIRONMENT INFO \033[0m\033[32m");
for (int i = 0; i < 50; ++i) out.print('\u2500');
out.println("\033[0m");
String w = "\n\033[36m %-16s\033[0m: \033[33;1m%s\033[0m";
final String OS = osNAME + " - " + osVER;
out.format(w, "OS Platform", OS );
out.format(w, "User Home", userHOME);
out.format(w, "Work Directory", appCWD );
out.format(w, "Application Dir", appDIR );
out.format(w, "Java Runtime", javaHOME);
if (args.length > 0)
for (int i = 0; i < args.length; ++i)
out.format("\n\033[35;1m Argument #%02d\033[0m : "
+ "\033[31;1m%s\033[0m", i+1, args[i]);
out.println();
System.exit(0);
}
This will bring a bit of colour to your life, and will work the same in POSIX-like shells where UTF-8 is enabled — the default on modern systems, and Linux and MacOS in particular:
You can copy cvtjava.exe
to bin\Template.exe
and then run: ‘bin\Template
‹args›’, and even make a Windows shortcut to it, if you want — that is one advantage of an .exe
launcher. All the normal java
commands work, so you can try:
cvtjava -cp bin;. Template ‹args›
cvtjava -cp bin\Template.jar;. Template ‹args›
cvtjava -XshowSettings
cvtjava -help
For each of the above commands, replace cvtjava
with java
to prove that they work the same way. The only difference will be that you see no colours and the display is not cleared when running the example, because the escape sequences are not processed.
If you prefer a library solution, Jansi is simple, portable and will work on versions of Windows older than 10. A library that uses Jansi, but also offers line input, is JLine, which is useful for controllable input in console applications. Neither sets code page 65001
for UTF-8, which must still be done manually.
Summary
From this point, we will assume that you have a Java 8 SDK at hand, and have been able to compile and run the two example applications presented above. Do not continue until you are completely comfortable with creating directories for your projects, creating and editing Java source files, compiling your programs, and running your programs. The basic structure of a Java source file is simple, but do try to remember it.
From a syntactical point of view, you only have to know the following:
Only one
public
class per.java
source file is allowed, and the class name must exactly match the source file name, apart from the.java
extension.Formatting code is your responsibility, and important if you want to be taken seriously. Consistently indent your block levels, and use open lines to provide some logical cohesiveness.
Use spaces around operators, and keep your lines to a reasonable length.
Start using Javadoc-style comments as soon as possible. Write at least one Javadoc comment:
/** ‹one-line-description›.…*/
before anypublic
member, including yourclass
itself.Keep non-Javadoc in-line code comments short — rather write readable code.
Do not at this point worry about the numerous classes and packages available. The first order of business is to learn the syntax and structure of Java programs. Along the way, as a matter of practicality, several general-purpose classes will be introduced.
2017-12-27: Edited. [jjc]
2017-12-23: Incus Launcher. Reorganisation. [brx]
2017-12-20: Created. [brx]