slanted W3C logo

Day 03 — Strings, chars, and Java Arithmetic

Arithmetic in Java looks pretty much like the arithmetic you learned in math, but there are some surprises you need to know about.

String Literals

Any sequence of characters surrounded by double quotes is called a string literal. Examples:

"cse1020"
"Java By Abstraction"
""

The type of a string literal is String, which we study in detail in Chapter 6.

We have already seen that System.out.print and System.out.println can be used to print string literals.

Characters

A string is made up of individual characters. The type of an individual character is char.

char literals come in 3 forms. The easiest to understand is a single character between single quotes:

'A'
'a'
'+'

Special Characters

Notice that the single quote and double quote are used by Java to indicate char and String literals. This begs the question: How do create Strings such as:

Bart said, "Don't have a cow, man."

that contain single and double quotation marks?

Java uses a backslash to indicate an escape sequence for a small number of special characters.

'\''        // char literal for '
'\"'        // char literal for "
'\\'        // char literal for \
'\t'        // char literal for tab
'\n'        // char literal for line feed (newline on linux and OS X)

See Figure 1.11 in the textbook for the complete list of special characters.

Special Characters: Examples

Bart said, "Don't have a cow, man."

System.out.println("Bart said, \"Don\'t have a cow, man.\"");


'\t' is the tab character

System.out.println("\'\\t\' is the tab character");

Unicode Characters

Unicode is a standard for representing text expressed in most of the world's writing systems. The basic idea is to map the integers 0 through 65,535 to individual characters.

Primitive Integer Types

Some types are built into the Java language. These types are called the primitive types.

The primitive types that can hold integer values are:

byte and short will not really be used in 1020.

A long literal is an integer number followed immediately by L.

long zero = 0L;
long negativeFive = -5L;
long thousand = 1000L;

Arithmetic Operators for int Types

Assume that you have the following declarations for each example in the table below:

int x = 14;
int y = -7;
Operator Name Example Value
+ unary plus operator +x
+y
14
-7
- unary minus operator -x
-y
-14
7
* multiplication operator x * y -98
/ division operator x / y -2
% remainder operator x % y 0
+ addition operator x + y 7
- subtraction operator x - y 21

Arithmetic Operators for long Types

Assume that you have the following declarations for each example in the table below:

long x = 14;
long y = -7;
Operator Name Example Value
+ unary plus operator +x
+y
14L
-7L
- unary minus operator -x
-y
-14L
7L
* multiplication operator x * y -98L
/ division operator x / y -2L
% remainder operator x % y 0L
+ addition operator x + y 7L
- subtraction operator x - y 21L

Closure

Java guarantees that if you apply a:

This property is called closure.

Surprise!

How do you represent the passage of time on a computer? A widely used method is to store the number of seconds that have elapsed since a certain date.

Assuming that there are exactly 24 hours in a day and 365 days in a year, write a Java program that uses int literals (or variables) to calculate the:

  1. number of seconds in a year
  2. number of seconds in 70 years

Your program should use int variables, and it should print the results to the console.

Year 2038

Mathmatical Value Java Value
seconds per year 31 536 000 31536000
seconds in 70 years 2 207 520 000 -2087447296

Many existing operating systems represent the passage of time using an integer type that is similar to Java's int. Such systems measure time elapsed since midnight January 1, 1970. The Year 2038 Problem refers to the fact that this time keeping system fails on January 19, 2038 (a bit more than 68 years after the starting date of January 1, 1970).

Overflow

Closure requires that the result of an arithmetic operation with two int literals or variables also be of type int. When a value falls outside of the range that the int type can represent the result is arithmetic overflow (the same can be said for long).

Java ensures closure by treating the range as circular (adding 1 to the maximum int value produces the minimum int value, and subtracting 1 from the minimum int value produces the maximum int value).

public class IntOverflowExample
{
   public static void main(String[] args)
   {
      int max = Integer.MAX_VALUE;
      System.out.println(max + 1);

      int min = Integer.MIN_VALUE;
      System.out.println(min - 1);
   }
}

Integer Division

The Java division operator is the / symbol.

Satisfying closure means that dividing two int variables must produce an int result. Java accomplishes this by discarding the fractional part of the result:

Expression True Division Java Division
6 / 2 3 3
7L / 2L 3.5 3L
1 / 2 0.5 0
-9 / 5 -1.8 -1
9L / -5L -1.8 -1L
3 / 0 ArithmeticException

Integer Remainder

Java also provides an operator to compute the remainder after division. The remainder operator is the % symbol.

Java Remainder Expression Java Remainder
6 % 2 0
7L % 2L 1L
1L % 2L 1L
-9 % 5 -4
9 % -5 4
3 % 0 ArithmeticException

Your Turn

Write a Java program that computes the number of quarters, dimes, nickels, and pennies you would need to make 94 cents. You should compute the number of quarters first, followed by the number of dimes, followed by the number of nickels, followed by the number of pennies.

Unary int Operators

The operators we have seen so far are called binary operators because they require two operands. Java defines six unary operators that require one operand.

Unary Plus Operator

The unary plus operator + simply indicates a positive value. Note that you cannot use the operator to convert a negative value to a positive value; thus, this operator does not do anything when you use it on an int literal or variable.

The following program prints the number 17 on three lines:

public class IntUnaryPlusExample
{
   public static void main(String[] args)
   {
      int x = 17;
      System.out.println(x);

      // unary plus applied to an int literal
      int y = +17;
      System.out.println(y);

      // unary plus applied to an int variable
      y = +x;
      System.out.println(y);
   }
}

Unary Minus Operator

The unary minus operator - negates an expression.

The following program prints the number -17 on two lines:

public class IntUnaryMinusExample
{
   public static void main(String[] args)
   {
      int x = 17;

      // unary minus applied to an int variable
      y = -x;
      System.out.println(y);

      // unary minus applied to an expression
      y = -(14 + 3);
      System.out.println(y);
   }
}

Unary Increment and Decrement Operators

A common occurrence in computer programming is increasing (incrementing) or decreasing (decrementing) the value of a variable by 1. Java provides the increment operator ++ and the decrement operator -- that can be used immediately before or after a variable of type int.

public class IntIncrementDecrementExample1
{
   public static void main(String[] args)
   {
      int x = 0;
      
      ++x;
      // the value of the variable named x is now 1

      --x;
      // the value of the variable named x is now 0

      x++;
      // the value of the variable named x is now 1
      
      x--;
      // the value of the variable named x is now 0
   }
}

Notice that the placement of the operator (before and after the variable) was unimportant in this example. The placement becomes important when you apply the operator to a variable that is used in a larger expression.

Prefix Unary Increment and Decrement Operators

The prefix version of the operator occurs when the operator is placed in front of the variable. Java uses the incremented or decremented value of the variable in the expression for prefix increment or decrement.

Expression Value of y Final Value of x
int x = 0;
int y = 10 + ++x;
10 + (1) ⇒ 11 1
int x = 5;
int y = --x + 3;
(4) + 3 ⇒ 7 4
public class IntPrefixIncrementExample
{
   public static void main(String[] args)
   {
      int x = 10;
      System.out.println(++x);
      // should print 11
   }
}

The value of the expression ++x is the value of x incremented by 1.

Postfix Unary Increment and Decrement Operators

The postfix version of the operator occurs when the operator is placed after the variable. Java uses the current value of the variable in the expression for postfix increment or decrement.

Expression Value of y Final Value of x
int x = 0;
int y = 10 + x++;
10 + (0) ⇒ 10 1
int x = 5;
int y = x-- + 3;
(5) + 3 ⇒ 8 4
public class IntPostfixDecrementExample
{
   public static void main(String[] args)
   {
      int x = 10;
      System.out.println(x--);
      // should print 10
   }
}

The value of the expression x-- is the current value of x.

Operator Precedence

When you use multiple operators in the same expression you need to consider the order that the operators are evaluated. Each operator has a precedence level; operators with a higher precedence level are evaluated before ones with a lower level.

Precedence Operator
highest ++, -- postfix operators
++, --, +, - prefix unary operators
*, /, % multiply, divide, remainder
+, - addition, subtraction
lowest = assignment

Like regular arithmetic, multiplication and division (and remainder) have higher precedence than addition and subtraction.

Like regular arithmetic, expressions inside of parentheses are always evaluated first.

Precedence Examples

Assume that for each of the following examples shown in the table below we have the declarations:

int x = 10;
int y = 15;
Expression Evaluation
5 + x * y 5 + (x * y)
5 + (10 * 15)
5 + 150
155
++x * y (++x) * y
11 * y
11 * 15
165
y-- * (x - 8) y-- * (10 - 8)
y-- * 2
15 * 2
30

Association

Expressions with multiple binary operators (addition, subtraction, multiplication, division, remainder) of the same precedence are evaluated from left to right. These operators are said to be left-associative.

Assume that for each of the following examples shown in the table below we have the declarations:

int x = 10;
int y = 15;
Expression Evaluation
5 + x + y (5 + x) + y
(5 + 10) + y
15 + y
15 + 15
30
x * 6 / 2 % y (x * 6) / 2 % y
60 / 2 % y
(60 / 2) % y
30 % y
30 % 15
0
50000 * 50000 / 50000 (50000 * 50000) / 50000
-1794967296 / 50000
-35899
50000 / 50000 * 50000 (50000 / 50000) * 50000
1 * 50000
50000

An Arithmetic Quiz Program

You can test your understanding of operator precedence and association by running the ArithmeticOperatorGame.

  1. Download the two Java source code files to your Working folder:
    ArithmeticOperatorView.java
    ArithmeticOperatorGame.java
  2. Compile the source code files. You can compile both at the same time with the command:
    javac ArithmeticOperator*java
  3. Run the program with the command:
    java ArithmeticOperatorGame

Widening Conversions

It makes sense that you can store an int value in a long variable

int anInt = 50;
long aLong = anInt;

In the above example, nothing happens to the variable named anInt. The value stored in anInt is copied, converted to type long, and stored in aLong.

Conversion of int to long is called a widening conversion, and are always performed automatically by the compiler when needed.

Narrowing Conversions

Storing a long in an int variable is dangerous (because the range of legal values is much smaller for int).

Conversion of long to int is called a narrowing conversion, and is never performed automatically by the compiler.

If you need to perform a narrowing conversion, you can do so by using a cast:

long seventyYrsInSecs = 60L * 60L * 24L * 365L * 70L;
int secsPerYr = (int) (seventyYrsInSecs / 70L);

(int) converts whatever is immediately to the right to type int.

Casting a long value to an int value will produce unusual results if the original long value does not fall in the range allowed by int.

Mixing int and long with Operators

If you use an arithmetic operator with an int and a long operand, the Java compiler will automatically promote the int value to type long. The resulting value of the operation will be have type long.

public class MixedIntLongExample
{
   public static void main(String[] args)
   {
      long x = 5 + 100L;

      // next statement will cause a compilation error
      int y = 5 + 100L;
   }
}

In the above example, the expression 5 + 100L will be evaluated by the compiler as:

⇒ (long)(5) + 100L
⇒ 5L + 100L
⇒ 105L

The resulting long value cannot be assigned to the int variable y without a cast.

Self Check

  1. Can you compile and run all of the example programs shown in today's slides? Do you understand what they are trying to show?
  2. Do you understand the concepts listed in the Summary of Key Concepts on page 35 of textbook (concepts 12—17)?
  3. Can you answer the Review Questions on page 36 of the textbook (questions 19 and 20)?
  4. Can you do Exercises 1.16, 1.17, 1.18, and 1.19 in the textbook?

To Do For Next Lecture

  1. Finish reading Chapter 1 in the textbook.
  2. Explain the output of the program shown below:
    • taken from the book Java Puzzlers by Joshua Bloch and Neal Gafter
public class LongDivision
{
   public static void main(String[] args)
   {
      // milliseconds in a day
      long millisPerDay = 1000 * 60 * 60 * 24;

      // microseconds in a day
      long microsPerDay = 1000 * 1000 * 60 * 60 * 24;

      // prints 1000?
      System.out.println(microsPerDay / millisPerDay);
   }
}