AP Computer Science

Unit 2: Programming Basics: Output, Calculations, Data Types, Input

Topics covered in this unit

After completing this unit you will:

2.0. Overview

Computers need to do calculations, and they need to be able to communicate with us. This introductory unit covers everything you'll need to know to get your computer to give you output, to calculate numeric values, and to accept input.

Let's get started.

  1. Java
  2. Text editing
  3. "Hello, world!"
  4. Uploading to the server
  5. Intro to BlueJ IDE
  6. Producing Output
  7. Data Types and Variables
  8. Numeric Value Types
  9. Math and Calculations
  10. Errors, Debugging
  11. Getting Input
  12. Strings
  13. Methods

2.1. The Java Programming Language

Java is interesting in that it is both compiled AND interpreted. Take a program written in Java and compiling it converts it into bytecode, which is then run by a "Java Virtual Machine" (JVM), which has been written specifically for each operating system. When you install a Java Runtime Environment, you're putting a JVM on your computer that will interpret Java bytecode.

Java was developed in 1991 by Sun Microsystems for programming consumer devices, but it was never really used. In 1994 it was adapted for web browsers, and introduced to the world in 1995.

There are three reasons why Java is not the ideal language for beginners:

  1. It's not simple to write basic programs.
  2. It has been revised many times.
  3. You won't learn all of Java in one semester (or even one year).

Our goal is not to know Java, but to know how to think about programming, via Java.

2.2. Text Editing

A text editor is not a word processor like Microsoft Word or Google Docs. Text editors work with pure text, and have no ability to "make things look pretty" like a word processor does. There are no superscripts or subscripts, no underlining, no bold, and no italics.

The advantage to a text editor is that it handles unformatted plain text, which is easier for both computers and programmers to work with.

You can choose which text editor you want to work with in here. You have probably already installed VS Code, a popular text editor that many students in this class use. If not, go ahead and install that software using the instructions available from this page.

2.3. "Hello, World!" Java Program

Let's write our first Java program!

2.3.1. Writing the program in a text editor

Entering/Editing a program

Open up VS Code, open up an new (empty) file, and enter in the following program:

/** 
 * HelloWorld.java program
 * @author <your name>
 * @version <the date>
 */ 
 
public class HelloWorld
{
    public static void main(String[] args)
    {
        // Display a greeting to the user
        System.out.println("Hello, World!");
    }
}
    

Once you've written the program, save it onto your Desktop as HelloWorld.java

Some initial notes about Java:

Some specific notes about this program:

2.3.2. Editing, Compiling, and Running a Java Program

We've written our instructions for the computer to execute—now how do we actually get the computer to run that program?

Next we'll need to compile it, and finally run it.

Compiling and Running your program

2.3.3. Writing and Running Programs in General

Let's see if we can generalize what we've just done.

The Coding Cycle

Whether using a text editor/terminal or a more sophisticated IDE, the coding process is identical:

  1. Design the program (usually by hand, using pencil and paper)
  2. Write the program (using a text editor or IDE)
  3. Try to compile the program and debug whatever errors there might be
  4. Run a compiled version of the program to confirm that it's working better.
  5. Repeat these steps until you've tested the program sufficiently to have some confidence that it works as it's supposed to.

2.4. Uploading a program to the server

You should have already read the document on Turning in Work. Among other information in that document is a description of how to upload a document from your own computer to the server.

The easiest way to upload your document is probably the Secure Copy command, scp which has the format:

scp <source> <destination>

Here, because you're not currently logged in to the server, you'll need to provide your login credentials, and enter your password when asked.

$ scp HelloWorld.java studentID@server.name:~/forInstructor 
studentID@server.name's password:
HelloWorld.java                                         100% 1025     1.0KB/s   00:00

Complete your own HelloWorld.java program on your computer, and upload that program to the server for homework.

2.5. Intro to BlueJ

We've spent a little time working in a command-line environment, and this is how many developers spend the vast majority of their working day:

  1. entering a little code for a big project into a text editor
  2. compiling the source code and looking at the errors that are produced
  3. debugging it and then re-compiling it until no errors are produced
  4. running the compiled code and looking at the errors that are produced
  5. debugging it and then re-compiling and re-running it until it runs
  6. entering a little more code for the same project and starting the process all over again!

It seems a little tedious when you look at it that way, but if you get intrigued by the process of writing cool code, you'll love every minute of it—except when you hate it. And then it's time to step away from the computer and take a break.

We're going to be doing enough work on Java in here that it's going to be worth it for us to learn how to use an Integrated Development Environment, or IDE.

Integrated Development Environment (IDE)

An Integrated Development Environment is a set of software tools that work together to help software developers write programs. Those tools typically include a text editor, a compilation tool, and a debugger.

There are a number of excellent IDEs available for use with the Java language, including Eclipse, NetBeans, IntelliJ, ... For our purposes in here, I've chosen the BlueJ IDE for us to use. It's not as powerful or as complete as some of the other IDEs, but it's a great IDE for people first getting into development, and it's free. BlueJ is what you'll be using from here on our to write, test, and debug the programs you write.

2.6.0. Overview - Producing Output

We've already seen how Java provides us with a means of producing output using the System.out class.

System.out.println("Hello, World!");

We'll see some additional ways that Java can produce output soon. But first we need to know about the different types of data that Java can handle.

2.7.0. Data Types and Variables

For computers to be able to work with data, they need to be able to know what type of data they're working with: if we say 2 + 3 do we want the computer to print those characters? or do we want it to perform that calculation?

We also need to be able to keep track of the data that were working with in the computer's memory. Data stored in the computer's memory is referred to by a reference to that memory location called a variable.

Let's see how this all works.

2.7.1. Common Data Types

Types and Variables

In Java, every value has a type, and values are often stored in variables, which are named locations in the computer's memory. The name of the location is designated by an identifier.

Examples of three most common types that we'll be working with:

  1. int refers to an integer like 3, 147, 0, or -2
  2. double refers to a decimal value like 3.14, -14.2, or 1.43E7
  3. String refers to a sequence of characters enclosed in double quotes, like "Richard", "Hello, World", "T" (Note the capitalization on the term String.)

"Primitives"

In an Object-Oriented language such as Java, you may hear people say that "Everything is an Object!", but that isn't true. Data types such as integers (int) and floating-point numbers (double) are not objects. They are "primitives."

How do you know they're not objects? They don't have any methods. We'll learn more about this when we introduce Object-Oriented principles soon.

2.7.2. Variables are references to memory

Declarations

If you want to store a value in a variable, you have to first tell Java what kind of value will be stored in that variable. This is called a declaration, which is often at the beginning of a section of code. So to store the value 13 in a variable called luckyNumber, you first have to declare the variable and the type of data that you'll be storing in it:

int luckyNumber;    // declare that luckyNumber will be "storing" an integer

Assigning a value to a variable

Once you've established a variable, you can then use the assignment operator—in Java this is the equals sign = to identify the primitive or object that the variable will refer to. The value on the right becomes associated with the identifier on the left. (It is not a statement of equality like it is in math.)

luckyNumber = 13;   // the variable luckyNumber know refers to the int value 13

If you know that luckyNumber will start out with this value, you can combine these two steps into one step:

int luckyNumber = 13;

If you try this, though, you'll get an error:

int luckyNumber = "13";

The reason is that the number 13, with double quotes around it, is a String, not an integer. The Java compiler knows this and won't let you try to execute this command.

If you want to change the value that a variable refers to, use the equals sign again:

luckyNumber = 12;     // variable is already declared, don't need to do it again!

Whatever value was stored in luckyNumber before is no longer available to us. We have overwritten its value with this new, updated value.

There are rules for naming identifiers, some imposed by Java, and some we'll impose on ourselves.

Identifiers:

Common conventions:

2.8.0. Overview - Numeric Value Types

Computers can do a lot of things, but what they're best with is manipulating numbers. Here we're going to describe some of the different types of numeric data. Then we'll see how we can use those numbers to perform calculations.

2.8.1. An introduction to Number Types

We've began using data since the very first time we wrote a Java program, when we printed out the String "Hello, World!" Interestingly, the String is not one of the fundamental data types in Java, so... we've got a little bit still to learn in terms of our understanding of how values are represented.

There are 8 primitive data types in Java, types which are fundamentally different from objects. You should be aware of the list, although it's not necessary to memorize it.

The 8 Primitive Data Types of Java

2.8.2. Casts

As programmers, can we put an integer into a double variable? It turns out we can, and Java will do the conversion on its own just fine.

Can we put a double value into an integer variable? Java doesn't let us do this because it knows there's going to be a loss of data integrity if it tries to do that, so this is a syntax error.

We can tell Java, however, that we want to convert a double value to an integer by using a cast.

Definition of casting

Casting a data type consists of converting it from one type to another.

Example:

double balance = 13.75;
int dollars = (int) balance;    // example of casting

In the second line above, the double value of 13.75 is "cast" as an integer using the (int) instruction, forcing a conversion to a (truncated) integer value that can then be stored in the int variable dollars.

This ability to convert from one type of data to another is extremely important in Java, and we'll be exploring it in some detail later on in the course.

What if you want to round the number to the nearest integer before you store it, rather than just truncating the 0.75 part of it? Use the Math.round() method.

import java.lang.Math;
double balance = 13.75;
int dollars = (int) Math.round(balance);

2.8.3. Constants

Constants in Java

A constant in Java is a "variable" in memory whose contents are not going to change over the course of the program's running.

Examples:

To declare a constant value, one typically declares and instantiates the constant near the top of the program like this:

final double QUARTER_VALUE = 0.25;

The final keyword indicates that the value referred to by this constant will not be changing.

In Java, although the syntax of Java doesn't absolutely required it, we follow a number of conventions that have developed among Java programmers over time. These include:

2.8.4. Print Formatting

There are some cases where you'll want to format your output in a specific manner—displaying an amount of money with 2 decimal places, for example. For these situations, you want to use the printf method to format your output.

System.out.printf("The balance is $%7.2f", mySavings.getBalance());

Here, the string The balance is $ will be printed out, followed by the balance of mySavings, formatted so that it takes up 7 total spaces, including a decimal point and 2 digits after the decimal point. (The f indicates that this is a floating point number.)

The balance is $  20.43

If you increase the space, more spaces will be added to the left side. If the space allotted for printing the number is too small, the number will still be printed, but it will take up more space.

There are other formatting options as well, for different data types and different layouts. For more information consult our textbook or the Java API.

2.9.0. Overview - Numeric Calculations

Now that we can store numeric values in memory, let's look at the calculations we can do with those values.

2.9.1. Arithmetic Operations and Math Functions

Order of Operations in Java

Java's Order of Operations follows the standard mathematical order of operations.

Please Excuse My Dear Aunt Sally

() → exponents? → *,/ → +,–

The division operator / gives a double result as long as one of its operands is a double. Otherwise it given an int result with the remainder discarded. This can be very useful, except when you're not expecting it.

Examples of Division in Java

Math can be tricky in Java when you're first getting used to it. (This is why it's good to have tests to run your classes through.)

Programming division

Which of the following Java statements will correctly calculate the average of 3, 5, and 6?

  1. double average = (3 + 5 + 6) / 3;
  2. double average = (3 + 5 + 6) / 3.0;
  3. double average = ((double) 3 + 5 + 6) / 3;
  4. double average = (double) ((3 + 5 + 6) / 3);
  5. double average = (double) (3 + 5 + 6) / 3;

Show/hide answers

Only #2, #3, and #5 give the correct answer. Neither #1 nor #4 retain the decimal part of the average calculation. In #1, the integer value of 4 is calculated, and then stored in the variable average as 4.0. In #4, the integer division is determined before the result is cast as a double.

2.9.2. Other Math Operations

Use of these math operations requires importing the java.lang.Math library.

2.10. Overview - Errors, Debugging

It's claimed by some that a programmer spends only half their time writing programs—they spend the rest of their time debugging them.

We'll be discussing different strategies that you can use to mitigate some of those issues throughout this course. For now, let's just look at some of the common problems that you may run into while programming.

2.10.1. General classification of Errors

There are three types of errors that you'll need to keep an eye out for, and fixing errors is what we spend a good amount of time doing.

  1. Syntax errors are caught during compilation of your source code. The compiler will try to find as many errors as possible at one time, but realize that:
    • an error indicated for one line might have occurred on the previous line, and
    • a whole series of errors may be reported as a result of a single error earlier in the program.
    $ javac sum1to10.java
    test.java:8: error: ';' expected
                sum = sum + i
                             ^
    1 error
    $ 
  2. Run-time errors occur while a program is able to run, but doesn't do what it was designed or expected to do. Some run-time errors will cause the program to stop running—trying to divide by zero, for example, or text input being entered when numerical input was expected.
    $ java test
    Enter an integer: 4.0
    Exception in thread "main" java.util.InputMismatchException
    	at java.util.Scanner.throwFor(Scanner.java:909)
    	at java.util.Scanner.next(Scanner.java:1530)
    	at java.util.Scanner.nextInt(Scanner.java:2160)
    	at java.util.Scanner.nextInt(Scanner.java:2119)
    	at test.main(test.java:11)
    $
    Other run-time errors may be classified as...
  3. Logic errors, in which a program appears to be working just fine, but there's something wrong with the results it produces: a program that adds the numbers 1-10 and produces a result of 45 when the real answer is 55, for example. The only way to catch these types of errors is with testing.
    $ java sum1to10
    The sum of the integers 1 to 10 is 45
    Expected result: 55

One thing that helps with avoiding errors is defensive programming: writing well-structured code with comments, and progressively testing the code so that errors in one part don't end up cascading down into other areas of the program.

Check - Types of Errors

Identify what type of error—syntax, run-time, or logical—each of the following statements will result in.

Show/hide answers

  • System.out.println((10 * 2) / (5 - 2 - 3));
    is a Run-Time error. Dividing by 0 will cause the program to fail when it runs.
  • System.out.println(("The answer to 2 + 2 is" + (2 + 3));
    is a Logical error. The program is producing output, but the output is incorrect.
  • System.out.println("Hello, World!);
    is a Syntax error. There is a missing quote at the end of the string Hello, World!, so this program won't even compile.

2.10.2. Two types of math-related errors

2.10.2.1. Overflows

Overflow error

An overflow error occurs when the programmer attempts to store a number in a memory space that is too small. The size of the number exceeds the memory available for it, so the value that is stored in memory is incorrect.

An overflow error happens without any indication that you have a problem, so you have to anticipate the problem and fix it yourself without relying on the computer to give you an error message.

Demo: Overflow

In BlueJ, open up a project and enter the this in the Code Pad in the lower right corner of the project window:

int n = 1000000;
System.out.println(n * n);

If you're unaware of the fact that the largest value that can be stored in an int variable is 2 x 109, you'd expect the output to be 1 x 1012, or 1E12.

Instead, Java produces the output -727379968, which is incorrect. The correct answer was truncated to fit into the more limited space available for integers.

The solution to this is to use the long data type, which allows for integers with a greater number of decimal places. (We won't typically have need of the long type in here, and when using integers, will typically use the int type.)

2.10.3.2. Rounding

You might think that a solution to the overflow problem would be to use real numbers— floats and doubles—but they have issues of their own due to the challenges involved in representing decimal numbers in a binary computer.

Just as 1/3 can be written as 0.333333... which is an imperfect decimal representation of the fraction 1/3, computers have to represent decimal values in binary, where there is no exact representation for 0.1, for example.

Demo: Rounding

In BlueJ, open up a project and enter the this in the Code Pad in the lower right corner of the project window:

double f = 4.35;
System.out.println(f * 100);

This is a calculation so easy that we can do it in our heads: 4.35 x 100 = 435. But Java produces the result 434.999999999994, which is clearly incorrect.

Because of problems like this, the double type should not be used for calculations requiring a high degree of precision, although we'll use it in here for convenience's sake. If you really need precision, you'll want to use the BigDecimal type.

We'll be primarily using int and double types for our numerical analysis.

2.5.3. Some other things

If you really want to make precise calculations in any programming language, you typically have to apply some serious processing power to do it. In Java, the BigInteger and BigDecimal classes are used for that. Again, we're not going to use them in here, but if you find that you're in the position of having to calculate some really important values, you'll need to think about whether you should use these other strategies for you calculations.

2.11. Overview - Getting Input

We've already discussed how to use the System.out class to have our programs communicate to us. How can we allow our programs to also accept input from users?

2.11.1. Reading Input

It wasn't until Java 5 that Java's designers worried much about getting input from a keyboard—they'd spent more attention to developing a graphical interface, with windows, buttons, text fields, etc. System.out works great for getting output from a program, but System.in was neglected until relatively recently.

Using the Scanner class

To get keyboard input, use the Scanner class, which is imported using import java.util.Scanner;

In your program, to create a scanner object: Scanner in = new Scanner(System.in);

Once the object has been created, you can get input from the keyboard using one of the following four methods:

Play around with this for a few minutes using the CodePad in BlueJ. See if you can get the computer to ask you for input, enter something, and print it out.

Additional Scanner methods

Other methods from this class that you might find useful at some point:

2.12.0. Overview - Strings

The String class is not a primitive data type, but it's very commonly used, so let's take a quick look at some common ways of working with Strings.

2.12.1. Strings

The String class

A String is a sequence of characters enclosed in quotes—we've already seen that in our "Hello, World!" program. The quotes are not part of the string. Strings are objects, not primitives.

Because strings are objects they have methods that go with them. Especially useful is the .length() method, which returns the number of characters in the string. A string with no characters, "", is called the empty string or the null string, and has a length of 0.

You can use the + operator to concatenate strings to make longer strings. If you try this with a number and a string, the number is automatically converted to a string and then concatenated.

int n = 3 + 6;
System.out.println("The answer is " + n);

You can also take a string value and, if it is made of numeric characters, convert it back to a number:

int count = Integer.parseInt("19");
double price = Double.parseDouble("3.95");

Right after the .length() method, perhaps the single most useful String method is .substring(), which returns a subset of a given string. The syntax is:

s.substring(startInclusive, endExclusive)

This takes the String s and returns a subset of the string beginning at the position startInclusive and ending at the position just before endExclusive. Note that positions are counted starting with 0 (zero).

So,

String greeting = "Hello, World!";
String sub = greeting.substring(1, 4);
System.out.println(sub);      # Outputs characters 1 - 3: ell

Note the trickiness of the numbering system. Not only are the characters in the string numbered starting at 0, but there's an asymmetry in the stop and start values in the parameter: we start at the first value indicated, but stop one before the last value indicated.

If you leave off the second value in the substring call, it starts where you indicate, and copies all the way to the end of the string.

System.out.println(greeting.substring(7));  # prints the string World!

It's often convenient to be able to convert a String value to all lowercase or all uppercase characters.

String name = "Richard";
String upperCaseName = name.toUpperCase();  //  "RICHARD"
String lowerCaseName = name.toLowerCase();  //  "richard"

2.13.0. Overview - Methods

Definition: Method

A method is a logical collection of program instructions—a "block" of code surrounded by curly braces { }—that is referred to by the method name.

The method header describe the visibility of the method, what class it belongs to, what type of value it returns, its name, and its parameters, if any. For example:

public static boolean playAgain(String userName)
{
    .
    .
}

We'll learn more about what these things mean in the next few sections.

As we begin writing more advanced and complex problems, we're going to be writing lots of methods, and now is a good time to introduce the topic.

2.13.1. Methods for organizing code

Our programs up to this point have included a single method called main(). Every Java program that runs is required to have at least this one method, and it is required to have this particular name: main.

As our programs get longer, however, it will often be convenient for us to organize parts of the program into logical chunks that do some single identifiable task in a program. We can accomplish this by writing a method to do that task, and then calling the method from within our main() program.

2.13.1.1. Giving Instructions

Let's say that we have a game program that we're writing, and we want to introduce the user to the game and give them instructions at the start of the program. Once way we could do that would be to include all that code in the main() method:

public static void main(String[] args)
{
    System.out.println("Hi, and welcome to the Number Guessing Game!");
    System.out.println();
    System.out.println("In this game, the computer is going to think");
    System.out.println("of a number between one and ten.");
    System.out.println();
    System.out.println("Then, you'll have three chances to guess the number!");
    System.out.println("Each time that you don't guess the number I'll give you");
    System.out.println("a hint whether you've guessed too high or too low...");
    .
    .
    .

That's an awful lot of code in our main() method so far, and we've only gotten as far as giving them the instructions for the game. We haven't even started writing the code to actually play the game.

This could take screens and screens of code, so one use for methods is simply to separate out logical blocks of code.

Solution: Write a separate method that is responsible for greeting the user and giving them instructions.

Here's what that looks like:

public static void welcomeScreen()
{
    System.out.println("Hi, and welcome to the Number Guessing Game!");
    System.out.println();
    System.out.println("In this game, the computer is going to think");
    System.out.println("of a number between one and ten.");
    System.out.println()
    System.out.println("Then, you'll have three chances to guess the number!");
    System.out.println("Each time that you don't guess the number I'll give you");
    System.out.println("a hint whether you've guessed too high or too low...");
}

public static void main(String[] args)
{
    welcomeScreen();    // Says 'hi' and welcomes the user
    .
    .   // Additional code to play the game goes here
    .
    .
}

This is a much cleaner way to write the code for this program.

An even better way to write the program would be to have the main() method look something like this:

public static void main(String[] args)
{
    welcomeScreen();    // Says 'hi' and welcomes the user
    playGame();
    revealScore();
    sayGoodbye();
}

In this version, each component of the game-playing program is written in its own method, which makes the main() method much cleaner to read and understand.

As you begin to write more complex programs you'll quickly learn how to design your own methods that will make your code both easier to debug and to understand.

2.13.2. Methods that take parameters

Using methods to organize one's code is a valid strategy, but very often, methods are used in an even more powerful way: as functions that do stuff.

You're familiar with the idea of a function from mathematics, perhaps. A function takes values as inputs, performs some operations on those values, and produces output. Methods do exactly the same thing.

The primary means of getting information into a method is by including it as parameters in the parentheses after the method name:

public static void welcomeScreen(String name)
{
    System.out.println("Hello, " + name + ", and welcome to the Number Guessing Game!");
    .
    .
    .
}

Here we've rewritten the header for our welcomeScreen() method and indicated that this method, when it's called, can expect to have a String value given to it. Note that I've also rewritten my first line of the method so that it uses the name that was sent in.

Being able to send in input via a parameter is an enormously powerful capability.

2.13.3. Methods that return values

Another thing that a method sometimes needs to do is send back information to the program that called it. This is called "returning a value," and it's accomplished using a return statement.

Let's say we want to write a method that is going to ask the user to enter their name, and we want to send that name back to the main program so that it can be used elsewhere.

public static String getName()
{
    Scanner in = new Scanner(System.in);
    System.out.print("Your name: ");
    String name = in.next();
    return name;
}

The main program would look like this:

public static void main(String() args)
{
    String userName = getName();
    welcomeScreen(userName);
    .
    .
    .
}

2.13.4. Methods that take parameters and return values

In the style of a classic function, this kind of method takes parameters as input values and produces a result that is sent back.

Take a look at this function as an example:

/**
 * The multiple method takes two double values and returns their product
 */
public static double multiply(double n1, double n2)
{
    double product = n1 * n2;
    return product;
}

This isn't a great example of a method—if you want to multiply two numbers together, it's probably sufficient just to use n1 * n2 in your program rather than writing this special method and calling it. But there may be circumstances where you will want to write your own multiply() method—if you're calculating the dot-product or cross-product of two vectors, for example.

2.13.5. How do I know how to write a method?

You'll quickly learn how to identify the kind of method you should be writing, but at first it can be confusing. The two questions you need to ask when you write a method are:

  1. What information, if any, does this method need to operate?
    If it needs information to figure something out, you'll need to send that information in via parameters. Parameters will be declared in the method definition (including their type), and "arguments" that correspond to those parameters will need to be sent in when the method is called.
  2. What information, if any, does this method need to send back?
    If it's sending back a number, we'll need to return that number. If it's sending back a String we'll need to return that String.
    Note for Python programmers: Java only allows you to send back a single result. If you need to send back more information than what can be contained in a single variable, you'll have to develop a data structure that can contain that information. We'll see how to do that a little later on in the course.