1.2 Basic Java Features

Variables and Loops

The program below will print out the integers from 0 through 9.

void main() {
	int x;

	x = 0;
	while (x < 10) {
		IO.print(x + " ");
		x = x + 1;
	}
}

When we run this program, we see:

$ javac HelloNumbers.java
$ java HelloNumbers
$ 0 1 2 3 4 5 6 7 8 9 

Some interesting features of this program that might jump out at you:

  • Our variable x must be declared before it is used, and it must be given a type!

  • Our loop definition is contained inside of curly braces, and the boolean expression that is tested is contained inside of parentheses.

  • Our print statement is just IO.print instead of IO.println. This means we should not include a newline (a return).

  • Our print statement adds a number to a space. This makes sure the numbers don't run into each other. Try removing the space to see what happens.

Of these features the most important one is the fact that variables have a declared type.

Static Typing

Java is a statically typed language, which means that all variables, parameters, and methods must have a declared type. After declaration, the type can never change. Expressions also have an implicit type; for example, the expression 3 + 5 has type int.

Because all types are declared statically, the compiler checks that types are compatible before the program even runs. This means that expressions with an incompatible type will fail to compile instead of crashing the program at runtime.

The advantages of static typing include:

  • catching type errors earlier in the coding process, reducing the debugging burden on the programmer.

  • avoiding type errors for end users.

  • making it easier to read and reason about code.

  • avoiding expensive runtime type checks, making code more efficient.

However, static typing also has several disadvantages; namely:

  • more verbose code.

  • less generalizable code.

One of the most important features of Java is that all variables and expressions have a so-called static type. Java variables can contain values of that type, and only that type. Furthermore, the type of a variable can never change.

One of the key features of the Java compiler is that it performs a static type check. For example, suppose we have the program below:

Compiling this program, we see:

The compiler rejects this program out of hand before it even runs. This is a big deal, because it means that there's no chance that somebody running this program out in the world will ever run into a type error!

This is in contrast to dynamically typed languages like Python, where users can run into type errors during execution.

In addition to providing additional error checking, static types also let the programmer know exactly what sort of object he or she is working with. We'll see just how important this is in the coming weeks. This is one of my personal favorite Java features.

To summarize, static typing has the following advantages:

  • The compiler ensures that all types are compatible, making it easier for the programmer to debug their code.

  • Since the code is guaranteed to be free of type errors, users of your compiled programs will never run into type errors. For example, Android apps are written in Java, and are typically distributed only as .class files, i.e. in a compiled format. As a result, such applications should never crash due to a type error since they have already been checked by the compiler.

  • Every variable, parameter, and function has a declared type, making it easier for a programmer to understand and reason about code.

However, static typing also has several disadvantages, which will be discussed further in later chapters. To name a few:

  • More verbose code.

  • Less generalizable code.

Extra Thought Exercise

In Java, we can say System.out.println(5 + " ");. But in Python, we can't say print(5 + "horse"), like we saw above. Why is that so?

Consider these two Java statements:

and

The first one of these will succeed; the second will give a compiler error. Since Java is strongly typed, if you tell it h is a string, it can concatenate the elements and give you a string. But when h is an int, it can't concatenate a number and a string and give you a number.

Python doesn't constrain the type, and it can't make an assumption for what type you want. Is x = 5 + "horse" supposed to be a number? A string? Python doesn't know. So it errors.

In this case, IO.print(5 + "horse");, Java interprets the arguments as a string concatentation, and prints out "5horse" as your result. Or, more usefully, IO.print(5 + " "); will print a space after your "5".

For fun, you might consider (and look up) what happens if you do IO.println(5 + "10"); Do you think it's 510, or 15? How about IO.println(5 + 10);?

Defining Functions in Java

In languages like Python, functions can be declared anywhere, even outside of functions. For example, the code below declares a function that returns the larger of two arguments, and then uses this function to compute and print the larger of the numbers 8 and 10:

The equivalent Java program to the code above is as follows:

Here we observe:

  • Java function parameters must have a type.

  • Java functions can return only one value.

  • Java functions must have a declared return type. Note that the void in void main function is specifying that the return type of main is void, i.e. it returns nothing.

One downside of static types is the resulting verbosity. If we wanted to use larger on strings, we'd have to make another copy of the method that takes strings as input. And as we'll see later, Java gets even more verbose.

You might think that this sort of programming language will slow you down, and indeed it will, in the short term. Think of all of this stuff like static typing as safety equipment that we haven't really learned to appreciate. When we're building small programs, it all seems superfluous. However, when we get to building large programs, we'll grow to appreciate all of the added complexity.

As an analogy, programming in Python can be a bit like Dan Osman free-soloing Lover's Leaparrow-up-right. It can be very fast, but dangerous. Java, by contrast is more like using ropes, helmets, etc. as in this videoarrow-up-right.

Code Style, Comments, Javadoc

Code can be beautiful in many ways. It can be concise. It can be clever. It can be efficient. One of the least appreciated aspects of code by novices is code style. When you program as a novice, you are often single mindedly intent on getting it to work, without regard to ever looking at it again or having to maintain it over a long period of time.

In this course, we'll work hard to try to keep our code readable. Some of the most important features of good coding style are:

  • Consistent style (spacing, variable naming, brace style, etc)

  • Size (lines that are not too wide, source files that are not too long)

  • Descriptive naming (variables, functions, classes), e.g. variables or functions with names like year or getUserName instead of x or f.

  • Avoidance of repetitive code: You should almost never have two significant blocks of code that are nearly identical except for a few changes.

  • Comments where appropriate. Line comments in Java use the // delimiter. Block (a.k.a. multi-line comments) comments use /* and */.

The golden rule is this: Write your code so that it is easy for a stranger to understand.

Often, we are willing to incur slight performance penalties, just so that our code is simpler to grokarrow-up-right. We will highlight examples in later chapters.

Comments

We encourage you to write code that is self-documenting, i.e. by picking variable names and function names that make it easy to know exactly what's going on. However, this is not always enough. For example, if you are implementing a complex algorithm, you may need to add comments to describe your code. Your use of comments should be judicious. Through experience and exposure to others' code, you will get a feeling for when comments are most appropriate.

One special note is that all of your methods and almost all of your classes should be described in a comment using the so-called Javadocarrow-up-right format. In a Javadoc comment, the block comment starts with an extra asterisk, e.g. /**, and the comment often (but not always) contains descriptive tags. We won't discuss these tags in this textbook, but see the link above for a description of how they work.

As an example without tags:

The widely used javadoc toolarrow-up-right can be used to generate HTML descriptions of your code.

Last updated