Variables

Variables are convenient handles for accessing memory. We don't need to mess with memory addresses:

Figure 66. Variables: Handles to memory Slide presentation

Declaring a variable requires a type name like double and an identifier:

// Variable declaration:
//     Variable's type is double
//     Variable's name is «pi» (identifier)

double pi;
{type name} {variable name} ;

We may assign values to variables or build expressions like pi * 2.0 * 2.0 :

Figure 68. Declare, assign and use Slide presentation
double pi;      // Variable declaration

pi = 3.1415926; // Assigning value to variable

// Print a circle's area of radius 2.0

System.out.println(pi * 2.0 * 2.0);

Figure 69. Combining declaration and initialization Slide presentation
Separate declaration and initialization
double pi;      // Declaration of variable pi

pi = 3.1415926; // Value assignment
Combined declaration and initialization
double pi = 3.1415926;

Figure 70. Multiple variables of same type Slide presentation
int a;
int b = 22;
int c;

being equivalent to either of:

Compact Multiple lines
int a, b = 22, c;  
int a,
    b = 22,  
    c;

Figure 71. Identifier in Java: Slide presentation
  • Variable names.

  • Class names

  • Method names, e.g.:

    public static void main(String [] args)


Figure 72. Identifier name examples: Slide presentation
Identifier rules Legal Illegal
  • Start with a letter, _ or $

  • May be followed by letters, digits, _ or $

  • Must not match a reserved keyword or literal

  • $test

  • _$

  • count

  • blue

  • 2sad

  • switch

  • true


Figure 73. Java keywords. Slide presentation
Reserved keywords
abstract  char      else     if          long       return        this      while
assert    class     enum     goto        native     short         throw     _ (underscore)
boolean   const     extends  implements  new        static        throws  
break     continue  final    import      package    strictfp       transient  
byte      default   finally  instanceof  private    super         try  
case      do        float    int         protected  switch        void  
catch     double    for      interface   public     synchronized  volatile
Reserved boolean and null literal values
true   false   null   
Contextual keywords
exports  non-sealed opens    provides  requires  to          uses  when  yield
module   open       permits  record    sealed    transitive  var   with

Figure 74. Variable naming conventions Slide presentation
  • Start with a small letter like africa rather than Africa.

  • Use camel case e.g. myFirstCode.

    Variable naming conventions
  • Do not start with _ or $.


Figure 75. Constant variables Slide presentation

Modifier final prohibits changes:

final double PI = 3.1415926;
...
PI = 1.0; // Compile time error: Constant cannot be modified

Note

final variables by convention are being capitalized


Figure 76. Case sensitivity Slide presentation

Variable names are case sensitive:

int count = 32;
int Count = 44;
System.out.println(count + ":" + Count);

Resulting output:

32:44

exercise No. 11

Legal variable names

Q:

Which of the following names are legal variable names? If so, would you actually use them in your code?

Complete the following table and explain your decision with respect to the Language Fundamentals / variables section of [Kurniawan] .

Identifier Legal? (yes / no) Explanation / remark
for
sum_of_data
sumOfData
first-name
ABC
42isThesolution
println
B4
AnnualSalary
"hello"
_average
ανδρος
$sum

Tip

You may want to prepare a simple Java program testing the above names.

A:

Consider:

public static void main(String[] args) {
   int 42isThesolution = 6; // Syntax error on token "42", delete this token
}

Unfortunately this message does not explain the underlying cause: It does not hint towards an illegal identifier name.

One indication of a sound compiler implementation is its ability to provide meaningful, self explanatory error messages.

Identifier Legal? (yes / no) Explanation / remark
for no for is a Java keyword.
sum_of_data yes -
sumOfData yes -
first-name no Operators like - or + must not appear in variable names.
ABC yes Discouraged by «Best practices» if non-constant (final): Non-constant variables should start with lowercase letters.
42isThesolution no Identifiers must not start with a number.
println yes println is a method's name but is no Java keyword.
B4 yes See «ABC» above.
AnnualSalary yes See «ABC» above.
"hello" no String delimiters must not be part of an identifier.
_average yes Discouraged by «Best practices»: Identifier starting with «_» should be reserved for system code.
ανδρος yes Perfectly legal Greek Unicode characters.
$sum yes Discouraged by «Best practices»: Identifier starting with «$» should be reserved for system code.
Figure 77. Define before use Slide presentation
Correct:
double f;
f = -4.55;
Wrong:
f = -4.55;
double f;

Figure 78. Type safety Slide presentation
int i = 2;
int j = i;   // o.K.: Assigning int to int
long l = i;  // o.K.: Widening conversion

i = l;       // Wrong: Narrowing

boolean b = true;
i = b;       // Error: int and boolean are incompatible types
i = 4.3345   // Error: Cannot assign double to int
i = "Hello"; // Even worse: Assigning a String to an int

Figure 79. Compile time analysis Slide presentation
byte b127 = 127; // o.K., static check
byte b128 = 128; // Wrong: Exceeding 127

Performing static range check

int a = 120;

byte b120 = a; // Error Incompatible types
               // Required: byte
               // Found:int

No static check on int variable's value


exercise No. 12

Benefits of final

Q:

We reconsider our code from Figure 79, “Compile time analysis ”:

int a = 120;

byte b120 = a; // Error Incompatible types
               // Required: byte
               // Found:int

Adding final solves the issue:

final int a = 120;

byte b120 = a;  // o.K.

Why does introducing a final modifier solves the fatal compile time error issue?

Tip

Read Static program analysis. Why does final help the compiler in code analysis?

A:

Modifying variable a to become final assures its initial value will never change. Thus from a Data-flow analysis point of view the two snippets are equivalent:

final int a = 120;

byte b120 = a;
byte b120 = 120;

The compiler is thus able to perform a compile time range check assuring the value of 120 to be within the interval [-128, 127].

Figure 80. Type inference (JDK 10) Slide presentation
var count = 30; // o.K., type can be inferred from int literal
        
var index;      // Wrong: No way to infer type here.
index = 3;

Figure 81. Forcing conversions Slide presentation
long l = 4345;

int i = (int) l; // Casting long to int
System.out.println("i carrying long: " + i);

double d = 44.2323;
i = (int) d; // Casting double to int
System.out.println("i carrying double: " + i);
i carrying long: 4345
i carrying double: 44

Figure 82. Watch out! Slide presentation
long l = 3000000000000000L;
int i = (int) l;
System.out.println("i carrying long:" + i);

double d = 44300000000000.0;
i = (int) d;
System.out.println("i carrying double:" + i);
i carrying long:-296517632
i carrying double:2147483647

Figure 83. Casting long to int Slide presentation

Figure 84. Don't worry, be happy ... Slide presentation

«C» programming language miracles:

#include <stdio.h>

void main(void) {
  double measure = 65234.5435;
  short velocity;
  velocity = measure;
  printf("Velocity=%d\n", velocity);
}

Uups:

Velocity=-302

Figure 85. ... and watch the outcome Slide presentation
... and watch the outcome
Development costs:

~$7 billion.

Rocket and cargo

~$500 million.

related video and explanations


Figure 86. From the report Slide presentation

The cause of the failure was a software error in the inertial reference system.

Specifically, a 64 bit floating point number relating to the horizontal velocity of the rocket with respect to the platform was converted to a 16 bit signed integer.

The number was larger than 32,767, the largest integer possible in a 16 bit signed integer, and thus the conversion failed.

Related video explanation


exercise No. 13

«C» vs. Java.

Q:

We reconsider the «C» code example from Figure 84, “Don't worry, be happy ... ”:

#include <stdio.h>

void main(void) {
  double measure = 65234.5435;
  short velocity;
  velocity = measure;
  printf("Velocity=%d\n", velocity);
}

Rewrite the same code in Java. Replace printf("Velocity=%d\n", velocity) by a System.out.println(...) statement. Answer the following two questions:

  1. You will encounter a compile time error not being present in »C«. Try to overcome it.

  2. After your correction the result will be -302 like in the »C« snippet. On contrary for a related double to int conversion the overflow behaviour is different:

    Code Output
    double d = 3000000000.0; // Larger than Integer.MAX_VALUE
    int i = (int) d;
    System.out.println(i);   // Result: Integer.MAX_VALUE
    2147483647

    This time we get an int's maximum value representing the closest possible value to 3000000000.0.

    If the velocity = measure assignment was behaving accordingly we should see an outcome of Short.MAX_VALUE or 32767 rather than -302.

    Explain this different behaviour.

A:

  1. Naively rewriting the »C« snippet in Java yields a compile time error:

    double measure = 65234.5435;
    short velocity;
    velocity = measure; // Error: Incompatible types. Required: short, Found: double
    System.out.println(velocity);

    Resolving this error requites a type cast. We also combine declaration and assignment of velocity:

    double measure = 65234.5435;
    short velocity = (short) measure; // Explicit double to short conversion, possible data loss

    Note

    This resolves the syntax error. However the overflow problem when converting a double 65234.5435 into a short of -302 still prevails.

  2. The referenced specification reads:

    A narrowing conversion of a floating-point number to an integral type T takes two steps:

    1. In the first step, the floating-point number is converted either to a long, if T is long, or to an int, if T is byte, short, char, or int as follows:

      ...

    2. In the second step:

      • If T is int or long, the result of the conversion is the result of the first step.

        This is the behaviour for double to int.

      • If T is byte, char, or short, the result of the conversion is the result of a narrowing conversion to type T (§5.1.3) of the result of the first step.

        This is the behaviour for double to short.

    So behind the scenes the velocity = (short) measure assignment is being decomposed into two steps:

    Code Output
    double measure = 65234.5435;
    
    // Step 1: double --> int
    int velocityInt = (int) measure;
    
    // Step 2: int --> short
    short velocity = (short) velocityInt;
    
    System.out.println("velocityInt=" + velocityInt + ", velocity=" + velocity);
    velocityInt=65234, velocity=-302

exercise No. 14

Assignment and type safety

Q:

We consider:

int i = -21;
double d = i;

This snippet shows correct Java code. However Figure 78, “Type safety ” suggests we should not be allowed to assign an int to a double value due to type safety.

Even worse: Swapping types yields a compile time error:

double d = 2.4;
int i = d; // Error: Incompatible types

Questions to answer:

  1. Explain on syntax level why is d = i is allowed but i = d causes an error? Hint: Read about widening and narrowing conventions.

  2. Whats the ratio behind this design decision? Hint: What would happen for larger double values?

A:

  1. The first code snippet uses the widening conversion: When assigning d = i the Java compiler implicitly converts a four byte int into an eight byte double value.

    In contrast there is no automated narrowing from double to int hence causing a compile time error.

  2. Turning a double into an int is more cumbersome: The expression e.g. i = 3.5 could be evaluated by agreeing on a specific rounding prescription. But what about e.g. i = 3457357385783573478955345.45 ? A Java int's maximum value is 2 31 - 1 unable to accommodate the double value in question by far.

    Conclusion: Java disallows double to int assignments unless using a so called cast (explicit type conversion):

Caveats using explicit casts:

  1. double d = 2.6;
    int i = (int) d; // Explicit cast double to int
    System.out.println("Result: " + i);
    Result: 2

    Notice the result of 2 rather than 3 as you might have expected assuming common rounding convention rules. Rounding does not happen unless you explicitly use methods like e.g. Math.round().

  2. double d = 3_000_000_000.;
    int i = (int) d; // Explicit cast double to int
    System.out.println("Result: " + i);
    Result: 2147483647

    This truncation of 3 billion to 2147483647 is due to the latter value being the largest possible int value to be represented in Java.

Java provides meta information on types:

exercise No. 15

Inventing tinyint.

Q:

Suppose Java was offering a hypothetic signed integer type tinyint using 3-bit 2-complement representation.

  1. Write down all possible decimal values among with their corresponding binary representation.

  2. Perform the following additions on binary level:

    • 1 + 2

    • -4 + 2

    • -1 - 2

    • 3 + 1

    Hint by example: -4 + 3 is:

     1   100
     2  +011
    --  ----
     ?   111  

    What is 3-bit two complement 111 in decimal?

A:

  1. Given n=3 in three bit two complement notation as usual possible values range from - 2 ( 3 - 1 ) to 2 ( 3 - 1 ) - 1 :

    Decimal Two-complement
    3 011
    2 010
    1 001
    0 000
    -1 111
    -2 110
    -3 101
    -4 100

    Thus the example hint value 111 is indeed decimal -1 equalling -4 + 3 as expected.

  2. 1 + 2
     1   001
     2  +010
    --  ----
     3   011
    -4 + 2
    -4   100
     2  +010
    --  ----
    -2   110
    -1 - 2
    -1     111
    -2    +110
    --  ------
    -3    1101 (See comment below)

    In 3-bit two complement representation the leftmost bit at position 4 will be discarded. The actual result is thus 101 as expected.

    3 + 1
     3   011
     1  +001
    --  ----
    -4   100 Surprise! See comment below

    This is actually an overflow: In 3-bit two complement representation the highest representable decimal value is 3 being equal to 2 3 - 1 - 1 . Trying to add a value of 1 leads to disaster and in suitable circumstances may cause a US$370 spacecraft plummeting from the sky! Excerpt from the Ariane 5 flight 501 failure report:

    The internal SRI software exception was caused during execution of a data conversion from 64-bit floating point to 16-bit signed integer value. The floating point number which was converted had a value greater than what could be represented by a 16-bit signed integer.

exercise No. 16

An int's minimum and maximum value

Q:

In this exercise we look at an int's the largest and smallest (negative) possible value.

A Java int is internally being represented by 4 bytes. 00000000_00000000_00000000_00000101 2 for example represents the decimal value 5.

Java implements negative values using Two's complement representation. We provide some values:

Table 1. 4 Byte Two's complement representation of int values.
Two complement representation Decimal representation
00000000_00000000_00000000_00000000 0
01111111_11111111_11111111_11111111 2 32 - 1 - 1 (Maximum)
10000000_00000000_00000000_00000000 - 2 32 - 1 (Minimum)
11111111_11111111_11111111_11111111 -1

Use int literals in binary representation like e.g. 0B1100 in the Language Fundamentals / Literals section of [Kurniawan] in order to write an int's minimum and maximum possible value to standard output.

public static void main(String[] args) {

  int minumum = ... , //TODO: provide values by
  maximum = ...;  // binary int literals

  System.out.println("Minimum:" + minumum);
  System.out.println("Maximum:" + maximum);
}

A:

We insert Two's complement representations of minimum and maximum int values according to Table 1, “4 Byte Two's complement representation of int values.”.

public static void main(String[] args) {

  int minumum = 0B10000000_00000000_00000000_00000000,
      maximum = 0B01111111_11111111_11111111_11111111;

  System.out.println("Minimum int value:" + minumum);
  System.out.println("Maximum int value:" + maximum);
}

BTW: The JDK does provide maximum value, minimum value and related information for char, byte, short and int primitive data types within their corresponding Character, Byte, Short and Integer classes. You may want to execute:

System.out.println("int minimum:" + Integer.MIN_VALUE);
System.out.println("int maximum:" + Integer.MAX_VALUE);

System.out.println("int bytes:" + Integer.BYTES);
System.out.println("int size:" + Integer.SIZE);
Figure 87. Dynamic typing in PERL Slide presentation
$test = 44;  # Assigning an int
print $test, "\n";

$test = "Jim"; # Assigning a string
print $test, "\n";

$cmp = 43.55; # A float

if ($test == $cmp) { # comparing string against float
   print "Equal\n";
} else {
   print "Different\n";
}
44
Jim
Different

Figure 88. Dynamic typing in PERL, part 2 Slide presentation
$a = 2; # An integer
$b = 3; # Another integer

print '$a + $b = ', $a + $b, "\n";

$jim = "Jim";         # A string
print '$jim + $a = ' , $jim + $a, "\n";
$a + $b = 5
$jim + $a = 2

Figure 89. Using final Slide presentation
//Bad!
double pi = 3.141592653589793;
...
pi = -4; // Woops, accidential and erroneous redefinition
//Good
final double PI = 3.141592653589793;
...
PI = -4; // Compile time error:
         // Cannot assign a value to final variable 'pi'

Figure 90. Reference type examples Slide presentation
GpsPosition start = new GpsPosition(48.7758, 9.1829);
String name = "Simon";
LocalDate birtday = LocalDate.of(1990, Month.JULY, 5);