Time to get down to the nitty-gritty! Let’s start as pretty much every programming language introduction does: thinking about variables and the types of data they can hold.

Variables vs. Constants

How about we start with a nice underhand-pitch?

Question

What is a variable in programming? What is their purpose?

Variables hold whatever values we assign to them, and then can be referenced wherever they’re in scope whenever they are needed!

Note that since variables hold values, these values have a particular type, which is where one of our earlier distinctions of Java vs. Python comes into play:

Question

Recall that Java is said to be a manifest typed language — what does this mean?

Let’s start by looking at local variables, which exist only in the context of a method in which they’re declared.

Creating a new variable in Java can be performed in a couple of formats:

Toolkit

Variable declaration: tells the compiler that we want a new variable of the specified type by the syntax:

// Syntax:
<modifiers> type varName;
 
// Modifiers are optional; we'll see those later.
// Here's an example integer
int age;

Remark

Note: declared variables do not have a value and cannot be evaluated until they do.

So, for example, trying to System.out.println(age); above would yield a syntax error.

Toolkit

To initialize a variable, we can either use the assignment operator (=) during declaration, or after:

// With declaration:
int age = 31; // ugh I know, over the hill
 
// OR: Assignment after declaration
int age;
age = 31;

Remark

Stylistically, we prefer the “with declaration” initialization when possible, but syntactically the latter is fine.

Remember that modifier part of the syntax we mentioned above? Let’s look at one use, which is to define constants.

Toolkit

Constants are just like variables, but will never change values during the course of the program. Syntactically, they are declared with the final modifier, and stylistically, are named in ALL CAPS.

// Make constants of things that should never change:
final int SOCIAL_SECURITY = 555555555;
 
// Constants cannot have their value changed:
// [X] Syntax Error:
SOCIAL_SECURITY = 111111111;

Some notes on the above:

  • Constants should remain just that — so attempts to change them are considered errors!
  • We’ll see an application of constants later that ends up being good programming style — just be comfortable with the syntax for now.
  • There are other modifiers on variable declarations that we’ll see later.

Now that we know the var dec syntax, let’s talk about types a bit more!

Primitive vs. Reference Types (Objects)

Just like in Python, we can both create our own types or make use of the language’s standard ones.

Before we do anything too custom, let’s talk about the basic building block types: primitives.

Definition

There are 8 primitive types in Java that are the basic values upon which more complex types can be built.

Here’s an overview from your textbook with a few of my annotations:

Toolkit

Note that there are really just 4 primitive “categories” (Booleans, characters, ints, and decimals), but several differently-sized variants in the numerical quantities.

Question

Why do you think certain numerical types have different sizes/capacities?

That said, for all of the purposes we’ll see in this class, using ints for integer values and doubles for decimals will suffice.

Example

Initialize variables of each primitive type with as cringey of pun names as possible.

Don’t mind if I do…

// Primitive types (8 total):
boolean coolProf = false;
char acter       = 'A'; // [!] Note: single quotes
byte me          = 2;
short stuff      = 1;
int elligent     = 5;
long john        = 922337203;
float miBoat     = 3.14159;
double trouble   = 5.555555555;
 
// Reference Types / Objects (everything else)
String bean = "yum";
// Example of user-defined type (Card):
Card kingOfClubs = new Card(KING, CLUBS);

Remark

In other words, primitives make up the “atoms” of the Java type world from which more complicated objects, or “molecules / compounds”, are formed.

(I got a B+ in chemistry so don’t trust that analogy too much)

Type Conversions & Casting

Here’s another pretty big distinction from Python: what happens with type mismatches?

Question

What’s a type mismatch?

Here’s an example:

int inty = 5;
double dub = 4.4;
// [X] Syntax error: type mismatch
inty = dub;

Above, we’ve attempted to store a decimal value into an integer variable, which Java gets upset about.

Amusingly, the opposite direction is fine — storing an integer into a decimal value just tacks on a .0 and is groovy, but the above generates an error.

That said, when we want to stuff one value of one type into a variable of another, there are sometimes conversion methods available.

Toolkit

Type conversions / Casts provide a means of converting one type into another via the syntax:

(typeToCastTo) valueToCast

Different type conversion rules manifest differently, but the above is simple and can be fixed with the following:

int inty = 5;
double dub = 4.4;
// dub is converted to an int
inty = (int) dub;
// What gets printed here?
System.out.println(inty);

Question

Now, I haven’t mentioned the rule for how doubles get converted to ints, but what do you think happens?

Sometimes, we can exploit these type conversions implicitly like in the following example:

int inty = 5;
inty = 5 / 2;
// What gets printed here?
System.out.println(inty);

Toolkit

The above is known as integer division and can be used for a number of numerical applications.

Remark

Type conversion is not something you’ll need a lot, but you should consult Chapter 2 in your textbook for more info on type conversions.

So! That’s a good look at the essentials of variables and primitives, now let’s make a bunch of them!


Arrays

You might remember creating Lists of items in Python, which provide some ordered sequence of items in the collection:

# Python Lists:
listy = []
listy.append(1)
listy.append("two")
listy.append(3)
listy
=> [1, 'two', 3]

Note that listy began as an empty list, and then grew to accommodate the stuff we added, which consisted of both numbers and strings.

In Java, we have similar mechanisms, but (as Java tends to be) can be a bit pickier.

Definition

Arrays are the basic Java mechanism for storing ordered sequences of some data type.

Remark

However, they are importantly different from Python Lists in that they are:

  • Fixed Size: meaning that they can only hold some predefined number of items once initialized (this will actually be the first restriction we relax in our first data structure!).
  • Typed: meaning that, just like with Java variables, we must declare the types of items that are held within.

Array Declaration / Initialization

Toolkit

The syntax for initializing a new array with some given fixed size is:

<modifiers> type[] name = new type[size];

Example

To declare an array that has room for 3 ints, we would write:

int[] intArr = new int[3];

Some notes on the above:

  • The square-brackets [] by the type declaration indicate that the variable with the given name is a reference to an array, and not simply an int.
  • All values in an array initialized like this start with their default value, which for numerical primitives, is 0.
  • Note the new keyword, which we’ll see show up a lot later in the course: it indicates that a new object (i.e., non-primitive) is being created, with memory being reserved for it on the fly, and returns a reference to it.

If that last bullet has some words you don’t quite recognize yet, no worries — we’ll return to all of that in a bit.

Array Manipulation

Toolkit

Accessing / Setting array elements works the same as in Python: each element is indexed starting at 0, and then can be accessed using the bracket notation: arrName[index]

// Java Array Access:
int[] intArr = new int[3];
System.out.println(intArr[1]); // Print what's in index 1
intArr[1] = 5;
System.out.println(intArr[1]); // See it change from the default

Debug

Warning: just like in Python, you’ll get an error for trying to access some index that is not in the legal range!

int[] intArr = new int[3];
// [X] ILLEGAL Java Array Access:
System.out.println(intArr[3]); // There's no index 3 silly!
intArr[-1] = 5;                // Nor are negative indexes allowed

Typically, to avoid the above, we can check how large an array is by consulting its length property:

Toolkit

All arrays have a length property that returns an int describing its size, which can be accessed via the syntax: arr.length for some array named arr.

int[] intArr = new int[3];
System.out.println(intArr.length); // 3

Misc-array-ny

In the meantime, remember how in Python you could just initialize a List with the elements you wanted? Java’s got a trick for that too, but it uses a slightly different syntax:

# Python - list initialized with values
int_list = [1, 2, 3]
print(len(int_list)) # 3
// Java - list initialized with values
int[] intArr = {1, 2, 3}; // Note: curly braces {}
System.out.println(intArr.length); // 3

Question

Note how, in the above, we did not use the new keyword explicitly, nor declare the desired size of the array… but how big do you think intArr is above?

Now that we know about the primitives and arrays, let’s talk about one of the most ubiquitous non-primitive types: Strings!


Strings

Definition

Strings are non-primitive types that are just a sequence of chars… strung together to make text!

Toolkit

Strings are declared just like any other variable, except that they can be initialized by the special String literals, which are any text surrounded in double quotes "String literal":

String stringy = "initial text";

Remember earlier we said that primitives were like the “atoms” of the chemical world and “objects” were like the compounds?

Well, since we’re starting to think about how different data types are implemented in data structures (i.e., looking under the hood)…

Question

How do you think Strings are implemented from some combination of primitives?

In fact, in other, lower-level languages like C, Strings are explicitly modeled as arrays of chars… but since dealing with text is so common, higher-level languages like Java give us some shortcuts and convenience methods for dealing with text.

String Properties

That said, Strings in Java cannot be treated like arrays of characters, as they are objects that hide that implementation under the hood.

Instead, there are some properties of Strings we should talk about before we use them.

Toolkit

Java Strings are immutable, meaning their contained characters cannot be changed once they’ve been created.

String cantTouchThis = "abcd";
// [X] ILLEGAL: Syntax error
cantTouchThis[1] = 'z';
// OK: Can reassign a String variable to a new literal
cantTouchThis = "touch";

Toolkit

Unlike Arrays, or Strings in Python, we cannot use the bracket access syntax [] to even access characters in a String, nor do they have a .length property.

String notAnArray = "abcd";
// [X] ILLEGAL: Syntax error
System.out.println(notAnArray[2]);
// [X] ILLEGAL: Syntax error
System.out.println(notAnArray.length);

Yet, both of these features seem like important tools when dealing with text — what gives?

Well, these more complex String behaviors are baked into the String class’ methods, which we’ll look at next!

String Methods

Definition

Methods are function calls to objects, akin to giving commands that may return some value in response.

Toolkit

The syntax of a method call on any object is just like it was in Python:

object.methodName(inputs, ...);

Let’s look at some methods of Strings now!

Toolkit

The .length() method returns the number of characters in a String.

String bean = "green";
System.out.println(bean.length()); // 5

Other methods take arguments (inputs) like requesting a character at a particular index:

Toolkit

The .charAt(index) method returns the character at the given index (as long as it’s in-bounds).

String bean = "green";
System.out.println(bean.charAt(2)); // e

We won’t look at all of the methods available to Strings because… well.. there’s a lot of them!

The good news is that there are a couple of very convenient ways to find out what methods are available for any type’s objects… especially if your memory is as shit as mine!

Toolkit

The real way to look up a class’ methods is to consult the Javadocs (documentation) for it, which are, for all of the standard Java libraries, available online.

Take a look at the String Javadocs here!

Assignment

Toolkit

The lazy way to look up how to use a class’ methods is to use an IDE’s code suggestions.

For most standard Java IDEs, typing the method-call period after an object of a class will summon a convenient window with all of its available methods along with their documentation, like so:

Debug

There’s one EXTREMELY important difference in Strings between Python and Java: how you compare them for equivalence:

Toolkit

To determine whether or not two Strings are equivalent (i.e., have the same characters in the same order), use the .equals(otherStr) method, NOT the == operator.

String str = "same?";
 
// [X] Undefined behavior: may not always be true!
System.out.println(str == "same?");      // Sometimes not true
// OK: Safe way to compare Strings for equivalence
System.out.println(str.equals("same?")); // Always true

Debug

We’ll cover why this is the case in a later lecture, just remember: == is safe to compare primitive values for equivalence, but not objects!

String Conversions

Sometimes we find ourselves wanting to convert Strings to other types similar to the casting we saw earlier.

Debug

To make things more complicated, however, it turns out we cannot use the same syntax to cast between primitive and non-primitive types.

String numberOrString = "2";
// [X] Syntax error: cannot cast from String to int
int num = (int) numberOrString;

Luckily, there are methods available in some other Java classes to plug this gap, since it’s such a common task:

Toolkit

The Integer.parseInt(strToConvert) and Double.parseDouble(strToConvert) methods can be used to convert Strings to numerical primitives, returning the numerical equivalent of the String, if possible.

String numberOrString = "2";
// String properly converted to
int num = Integer.parseInt(numberOrString);
 
// [?] What gets printed below?
System.out.println(numberOrString + numberOrString);
System.out.println(num + num);

Those are the essentials with Strings! After the next lecture, we’ll run through a classwork that synthesizes it all!