Storing and using data with variables
We can think of a variable as a named storage box. We choose a name, perhaps variableA
. These names are kind of like our programmer's window into the memory of the user's Android device.
Variables are values in memory ready to be used or altered when necessary by using the appropriate name.
Computer memory has a highly complex system of addressing, which fortunately we do not need to interact with. Java variables allow us to devise our own convenient names for all the data we need our program to work with. The DVM will handle all the technicalities of interacting with the operating system, and the operating system will, in turn, interact with the physical memory.
So, we can think of our Android device's memory as a huge warehouse just waiting for us to add our variables. When we assign names to our variables, they are stored in the warehouse, ready for when we need them. When we use our variable's name, the device knows exactly what we are referring to. We can then tell it to do things such as: get variableA
and add it to variableC
, delete variableB
, and so on.
In a typical app, we might have a variable named unreadMessages
, perhaps to hold the number of unread messages the user has. We could add to it when a new message arrives, take away from it when the user reads a message, and show it to the user somewhere in the app layout, so they know how many unread messages they have.
Some situations that might arise are:
- User gets three new messages so add three to the value of
unreadMessages
. - User logs into app so use
Toast
to display a message along with the value stored inunreadMessages
. - User sees that a bunch of the messages are from someone she doesn't like and deletes six messages. We could then subtract six from
unreadMessages
.
These are fairly arbitrary examples of names for variables and as long as you don't use any of the characters or keywords that Java restricts, you can actually call your variables whatever you like.
In practice, however, it is best to adopt a naming convention so that your variable names will be consistent. In this book, we will use a loose convention of variable names starting with a lowercase letter. When there is more than one word in the variable's name, the second word will begin with an uppercase letter. This is called camel casing.
Something like:
unreadMessages
contactName
isFriend
Before we look at some real Java code with some variables, we need to first look at the types of variables we can create and use.
Types of variables
It is not hard to imagine that even a simple app will probably have quite a few variables. In the previous section, we introduced the unreadMessages
variable as a hypothetical example. What if the app has a list of contacts and needs to remember each of their names? We might then need variables for each contact.
And what about when an app needs to know whether a contact is also a friend, or just a regular contact? We might need code that tests for friend status and then adds messages from that contact into an appropriate folder so the user knows whether they were messages from a friend or not.
Another common requirement in a computer program, including Android apps, is the right or wrong calculation. Computer programs represent right or wrong calculations using true or false.
To cover these and many other types of data you might want to store or manipulate, Java has types.
Primitive types
There are many types of variables and we can even invent our own types as well. But for now, we will look at the most used built-in Java types. And to be fair, they cover just about every situation we are likely to run into for a while. These examples are the best way to explain types.
We have already discussed the hypothetical unreadMessages
variable. This variable is of course a number, so we have to tell the Java compiler this by giving it an appropriate type. The hypothetical contactName
will of course hold the characters that make up the contact name. Jumping ahead a couple of paragraphs, the type that holds a regular number is called int
and the type that holds name-like data is called String
. And if we try to store a contact name, perhaps "Ada Lovelace" in an int
like unreadMessages
, meant for numbers, we will certainly run into trouble, as we can see from the next screenshot:
As we can see, Java was designed to make it impossible for such errors to make it into a running program. With the compiler protecting us from ourselves, what could possibly go wrong?
Here are the main types in Java, then we will see how to start using them:
int
: Theint
type is for storing integers, whole numbers. This type uses 32 pieces (bits) of memory and can therefore store values with a magnitude a little in excess of two billion, including negative values too.long
: As the name hints at,long
data types can be used when even larger numbers are required. Along
type uses 64 bits of memory and 2 to the power of 63 is what we can store in this. If you want to see what that looks like, here it is: 9,223,372,036,854,775,807. Perhaps, surprisingly, there are uses forlong
variables but the point is, if a smaller variable will do, we should use it because our program will use less memory.Note
You might be wondering when you might use numbers of this magnitude. The obvious examples would be math or science applications that do complex calculations, but another use might be for timing. When you time how long something takes, the Java
Date
class uses the number of milliseconds since January 1, 1970. A millisecond is one thousandth of a second, so there have been quite a few of them since 1970.float
: This is for floating point numbers. That is, numbers where there is precision beyond the decimal point. As the fractional part of a number takes memory space just as the whole number portion, the range of a number possible in afloat
is therefore decreased compared to non-floating point numbers. So, unless our variable will definitely use the extra precision,float
would not be our data type of choice.double
: When the precision infloat
is not enough we havedouble
.boolean
: We will be using plenty of Booleans throughout the book. Theboolean
variable type can be eithertrue
orfalse
; nothing else. Perhaps Booleans answer questions such as:- Is the contact a friend?
- Are there any new messages?
- Are two examples for Boolean enough?
char
: A single alphanumeric character is stored inchar
. It's not going to change the world on its own but could be useful if we put lots of them together.Tip
I have kept this discussion of data types to a practical level that is useful in the context of this book. If you are interested in how a data type's value is stored and why the limits are what they are, then have a look on the Oracle Java tutorials site here: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html. Note that you do not need any more information than we have already discussed to continue with this book.
As we just learned, each type of data that we might want to store will require a specific amount of memory; so we must let the Java compiler know the type of the variable before we begin to use it.
The previous variables are known as the primitive types. They use predefined amounts of memory and so, using our warehouse storage analogy, fit into predefined sizes of storage box.
As the "primitive" label suggests, they are not as sophisticated as reference types.
Reference types
You might have noticed that we didn't cover the String
variable type that we previously used to introduce the concept of variables that hold alphanumeric data such as a contact's name.
Strings are one of a special type of variable known as a reference type. They quite simply refer to a place in memory where storage of the variable begins but the reference type itself does not define a specific amount of memory. The reason for this is fairly straightforward.
It's because we don't always know how much data will need to be stored in it until the program is actually run.
We can think of Strings and other reference types as continually expanding and contracting storage boxes. So won't one of these String
reference types bump into another variable eventually?
As we are thinking about the device's memory as a huge warehouse full of racks of labeled storage boxes, then you can think of the DVM as a super-efficient forklift truck driver that puts the different types of storage boxes in the most appropriate place.
And if it becomes necessary, the DVM will quickly move stuff around in a fraction of a second to avoid collisions. Also, when appropriate, Dalvik, the forklift driver, will even incinerate unwanted storage boxes. This happens at the same time as constantly unloading new storage boxes of all types and placing them in the best place, for that type of variable. Dalvik keeps reference variables in a different part of the warehouse to the primitive variables. And we will learn more details about this in Chapter 9, Object-Oriented Programming.
So, Strings can be used to store any keyboard character. Kind of like char
but of almost any length. Anything from a contact's name to an entire book can be stored in a single String
. We will be using Strings regularly, including in this chapter.
There are a couple more reference types we will explore as well. Arrays are a way to store lots of variables of the same type, ready for quick and efficient access. We will look at arrays in Chapter 13, Handling and Displaying Arrays of Data.
Think of an array as an aisle in our warehouse with all the variables of a certain type lined up in a precise order. Arrays are reference types, so Dalvik keeps these in the same part of the warehouse as Strings. We might, for example, use an array to store dozens of contacts in.
The other reference type is the class that we have already discussed but not explained properly. We will be getting familiar with classes in Chapter 9, Object-Oriented Programming.
Now we know that each type of data that we might want to store will require an amount of memory. Hence, we must let the Java compiler know the type of the variable before we begin to use it. We do this with a variable declaration.
Variable declaration
That's enough theory. Let's see how we would actually use our variables and types. Remember that each primitive type requires a specific amount of real device memory. This is one of the reasons that the compiler needs to know what type a variable will be. So, we must first declare a variable and its type before we attempt to do anything with it.
To declare a variable of type int
with the name unreadMessages
, we would type:
int unreadMessages;
That's it, simply state the type, in this case int
, then leave a space and type the name you want to use for this variable. Note also the semicolon ;
on the end of the line will tell the compiler that we are done with this line and what follows, if anything, is not part of the declaration.
Similarly, for almost all the other variable types, declaration would occur in the same way. Here are some examples. The variable names in the examples are arbitrary. This is like reserving a labeled storage box in the warehouse:
long millisecondsElapsed; float accountBalance; boolean isFriend; char contactFirstInitial; String messageText;
Variable initialization
Initialization is the next step. Here, for each type, we initialize a value to the variable. Think about placing a value inside the storage box:
unreadMessages = 10; millisecondsElapsed = 1438165116841l;// 29th July 2016 11:19am accountBalance = 129.52f; isFriend = true; contactFirstInitial = 'C'; messageText = "Hi reader, Just thought I would let you know that Charles Babbage was an early computing pioneer and he invented the difference engine. If you want to know more about him you can click this link www.charlesbabbage.net. Thanks, John";
Notice that the char variable uses single quotes '
around the initialized value while the String uses double quotes "
.
We can also combine the declaration and initialization steps. In the following we declare and initialize the same variables as we have previously, but in one step:
int unreadMessages = 10; long millisecondsElapsed = 1438165116841l;//29th July 2016 11:19am float accountBalance = 129.52f; boolean isFriend = true; char contactFirstInitial = 'C'; String messageText = "Hi reader, Just thought I would let you know that Charles Babbage was an early computing pioneer and he invented the difference engine. If you want to know more about him you can click this link http://www.charlesbabbage.net/. Thanks, John";
Whether we declare and initialize separately or together is probably dependent upon the specific situation. The important thing is that we must do both:
int a; // That's me declared and ready to go? // The line below attempts to output a to the console Log.i("info", "int a = " + a); // Oh no I forgot to initialize a!!
This would cause the following:
Compiler Error: Variable a might not have been initialized
There is a significant exception to this rule. Under certain circumstances variables can have default values. We will see this in Chapter 9, Object-Oriented Programming; however, it is good practice to both declare and initialize variables.