Home » Java (Page 2)

Category Archives: Java

Control Flows

The If Statement

1
if (condition) statement;

or

1
2
3
if (condition) {
    zero to many statements;
}

Causes “one thing” to occur when a specified condition is met.

The one thing may be a single statement or a block of statements in curly braces. The remainder of the code (following the if and the statement or block it owns) is then executed regardless of the result of the condition.

The conditional expression is placed within parentheses.

The following flowchart shows the path of execution:

If Statement Flowchart

if Statement Examples

Absolute Value

If we needed the absolute value of a number (a number that would always be positive):

Code Sample:

Java-Control/Demos/If1.java
1
2
3
4
5
6
7
8
9
10
11
12
public class If1 {
  public static void main(String[] args) {
    int a = 5;
    System.out.println("original number is: " + a);
    if ( a < 0 ) { a = -a; }
    System.out.println("absolute value is: " + a);
    a = -10;
    System.out.println("original number is: " + a);
    if ( a < 0 ) { a = -a; }
    System.out.println("absolute value is: " + a);
  }
}

Random Selection

Task: write a brief program which generates a random number between 0 and 1. Print out that the value is in the low, middle, or high third of that range (Math.random() will produce a double value from 0.0 up to but not including 1.0).

  • Although it is a bit inefficient, just do three separate tests: (note that Math.random() will produce a number greater than or equal to 0.0 and less than 1.0).

Code Sample:

Java-Control/Demos/If2.java
1
2
3
4
5
6
7
8
9
10
11
12
public class If2 {
  public static void main(String[] args) {
    double d = Math.random();
    System.out.print("The number " + d);
    if (d < 1.0/3.0)
      System.out.println(" is low");
    if (d >= 1.0/3.0 && d < 2.0/3.0)
      System.out.println(" is middle");
    if (d >= 2.0/3.0)
      System.out.println(" is high");
  }
}

The if ... else Statement

1
2
3
if (condition) statement;
else if { block } statement;
else { block }

The if … else Statement does “one thing” if a condition is true, and a different thing if it is false.

It is never the case that both things are done. The “one thing” may be a single statement or a block of statements in curly braces.

A statement executed in a branch may be any statement, including another if or if ... else statement.

If ... Else Statement Flowchart

This program tells you that you are a winner on average once out of every four tries.

Code Sample:

Java-Control/Demos/IfElse1.java
1
2
3
4
5
6
7
public class IfElse1 {
  public static void main(String[] args) {
    double d = Math.random();
    if (d < .25) System.out.println("You are a winner!");
    else System.out.println("Sorry, try again!");
  }
}

Nested if ... else Statements – Comparing a Number of Mutually Exclusive Options

You can nestif ... else statements, so that an if or else clause contains another test. Both the if and the elseclause can contain any type of statement, including another if or if ... else.

You can test individual values or ranges of values. Once an if condition is true, the rest of the branches will be skipped. You could also use a sequence of if statements without the else clauses (but this doesn’t by itself force the branches to be mutually exclusive).

Here is the low/middle/high example rewritten using if ... else

Code Sample:

Java-Control/Demos/IfElse2.java
1
2
3
4
5
6
7
8
9
10
11
12
public class IfElse2 {
  public static void main(String[] args) {
    double d = Math.random();
    System.out.print("The number " + d);
    if (d < 1.0/3.0)
      System.out.println(" is low");
    else if (d < 2.0/3.0)
      System.out.println(" is middle");
    else
      System.out.println(" is high");
  }
}

Similarly, we do not test the high third at all. The original version worked because there was no chance that more than one message would print; that approach is slightly less efficient because all three tests will always be made. In the if ... else version, comparing stops once a match has been made.

The switch Statement

A switch expression (usually a variable) is compared against a number of possible values. It is used when the options are each a single, constant value that is exactly comparable (called a case).

The switch expression must be a bytecharshort, or int. Cases may only be bytecharshort, or int values; in addition, their magnitude must be within the range of the switch expression data type and cannot be used with floating-point datatypes or long and cannot compare an option that is a range of values, unless it can be stated as a list of possible values, each treated as a separate case.

Cases are listed under the switch control statement, within curly braces, using the case keyword. Once a match is found, all executable statements below that point are executed, including those belonging to later cases; this allows stacking of multiple cases that use the same code.

The break; statement is used to jump out of the switch block, thus skipping executable steps that are not desired. The default case keyword catches all cases not matched above – note that the default case does not need to be the last thing in the switch. Note that technically speaking, the cases are labeled lines; the switch jumps to the first label whose value matches the switch expression.

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
switch ( <span class="Subst">expression</span> ) {
    case constant1:
        statements;
        break;
    case constant2:
        statements;
        break;
    . . .
    case constant3:
    case constant4:
        MeansTheSameAs3:
        statements;
        break;
    . . .
    [default:
        statements;]
}

switch Statement Examples

Code Sample:

Java-Control/Demos/Switch1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import util.KeyboardReader;
public class Switch1 {
  public static void main(String[] args) {
    char c = 'X';
    c = KeyboardReader.getPromptedChar("Enter a letter a - d: ");
    switch (c) {
      case 'a':
      case 'A': System.out.println("A is for Aardvark");
                break;
      case 'b':
      case 'B': System.out.println("B is for Baboon");
                break;
      case 'c':
      case 'C': System.out.println("C is for Cat");
                break;
      case 'd':
      case 'D': System.out.println("D is for Dog");
                break;
      default:  System.out.println("Not a valid choice");
    }
  }
}

Three points to note:

  • Stacking of cases for uppercase and lowercase letters allows both possibilities.
  • break; statements used to separate code for different cases.
  • default: clause used to catch all other cases not explicitly handled.

Here is a revised version that moves the default to the top, so that a bad entry is flagged with an error message, but then treated as an ‘A’ – note that there is no break below the default case.

Code Sample:

Java-Control/Demos/Switch2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import util.KeyboardReader;
public class Switch2 {
  public static void main(String[] args) {
    char c = 'X';
    c = KeyboardReader.getPromptedChar("Enter a letter a - d: ");
    switch (c) {
      default:  System.out.println("Not a valid choice - assuming 'A'");
      case 'a':
      case 'A': System.out.println("A is for Aardvark");
                break;
      case 'b':
      case 'B': System.out.println("B is for Baboon");
                break;
      case 'c':
      case 'C': System.out.println("C is for Cat");
                break;
      case 'd':
      case 'D': System.out.println("D is for Dog");
                break;
    }
  }
}

Another example is taking advantage of the “fall-though” behavior without a break statement.

Code Sample:

Java-Control/Demos/Christmas.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import util.KeyboardReader;
public class Christmas {
  public static void main(String[] args) {
    int day = KeyboardReader.getPromptedInt("What day of Christmas? ");
    System.out.println(
        "On the " + day + " day of Christmas, my true love gave to me:");
    switch (day) {
      case 12: System.out.println("Twelve drummers drumming,");
      case 11: System.out.println("Eleven pipers piping,");
      case 10: System.out.println("Ten lords a-leaping,");
      case 9: System.out.println("Nine ladies dancing,");
      case 8: System.out.println("Eight maids a-milking,");
      case 7: System.out.println("Seven swans a-swimming,");
      case 6: System.out.println("Six geese a-laying,");
      case 5: System.out.println("Five golden rings,");
      case 4: System.out.println("Four calling birds,");
      case 3: System.out.println("Three French hens,");
      case 2: System.out.println("Two turtle doves, and a ");
      case 1: System.out.println("Partridge in a pear tree!");
    }
  }
}

String

What is a String?

In java and unlike C++, the string data type is now an object type. Notice that the class name is starts with an uppercase. If you mess this up, Java will not know what you are referring to.

By it’s conception, a string is anything and everything grouped together between 2 double quotes. For example, “Hello world” is one string while “sdad anesd ccn ” is another.

Using Strings

Strings can be manipulated in numerous ways. The first is with some member functions of the string class. Let’s see an example first before we continue.

Example 1:
Different String functions

public class StringExample{

   public static void main(String args[]){

      String word;

      //assign the string to the variable:
      word = "Alexander";

      //preform some actions on the string:

      //1. retrieve the length by calling the
      //length method:
      int length = word.length();
      System.out.println("Length: " + length);

      //2. use the case functions:
      System.out.println("toUpperCase: " + word.toUpperCase());
      System.out.println("toLowerCase: " + word.toLowerCase());

      //3. use the trim function to eliminate leading
      //or trailing white spaces:
      word = word.trim();
      System.out.println("trim: " + word);

      //4. check for a certain character using indexOf()
      System.out.println("indexOf('s'): " + word.indexOf('s'));

      //5. print out the beginning character using charAt()
      System.out.println("first character: " + word.charAt(0));

      //6. make the string shorter
      word = word.substring(0, 4);
      System.out.println("shorter string: " + word);
   }
}

When you run the above program, here is the output that you will get:

Length: 9
toUpperCase: ALEXANDER
toLowerCase: alexander
trim: Alexander
indexOf('s'): -1
first character: A
shorter string: Alex

A lot certainly has happened in this program. Let’s observe some of the most used functions in the String class.

int length()

The length function will simply return the length of a string as an integer.

String toUpperCase()

The toUpperCase function will return the uppercase version of a string. Say you have a string “Welcome”. This function will return “WELCOME”.

String toLowerCase()

The toLowerCase function will return the lowercase version of a string. Say you have a string “Welcome TO Earth”. This function will return “welcome to earth”.

String trim()

The trim function will return the string without leading or trailing white space characters. Say that a string was ” hello “. There are 4 spaces in the front and 3 spaces at the end. The trim function would make this “hello”.

int indexOf(int ch)
int indexOf(int ch, int begin)
int indexOf(String ch)
int indexOf(String ch, int begin)

Notice that there are 4 different functions listed here. All of them preform the same overall action of returning an integer, which represents the FIRST OCCURRANCE of a character or String contained in that string. So say that we have the string “Hello” and we say indexOf(‘l’). This function will use the first function above and return 2. Notice it doesn’t reutrn 3.

We can also say, using the same string “Hello”, indexOf(“He”). It will return 0 as the string that you are searching for starts at index 0.

By default, if a string or character is not found in the string, the any of the functions will return -1.

char charAt(int index)

This function will look for a character at a specific index. It will return that character if it is found. Say we have the string “Hello” and we say charAt(4). It will return ‘o’ as that character is at index 4.

String substring(int begin)
String substring(int begin, int end)

Either of these functions will shorten a string when called. If no ending index is specified, it will return the rest of that string. Say we have the string “Hello there” and we say substring(4), the function will return “o there”. Let’s use substring(2,5), the function will return “llo”.

String Equalities

With Java, there are numerous methods they provide that check for two strings being equal. To show this, here is a small program that will check for a certain string as a command line argument.

Example 2:
String equalities

public class StringExample2{

   private static String word = null;
   private static String keyword = "HELLO";

   public static void main(String args[]){
	//standard error check:
	if(args.length < 1){
		System.out.println("Argument requires one word.");
		System.exit(1);
	}

	//retreive the sentence:
	word = args[0];

	//check for the keyword using different equals methods:
	if(word.equals(keyword)){
		System.out.println("equals true: "
                   + word);
	}
	if(word.equalsIgnoreCase(keyword)){
		System.out.println("ignoreCase true: "
                   + word);
	}

	//check for the keyword using different compareTo methods:
	if(word.compareTo(keyword) != -1){
		System.out.println("found using compareTo: " +
		   word.compareTo(keyword));
	}
	if(word.compareToIgnoreCase(keyword) != -1){
		System.out.println("found using compareToIgnoreCase: " +
		   word.compareToIgnoreCase(keyword));
	}
   }
}

This program will accept as a command-line argument, one word which we will call our “keyword”. It will then preform 4 checks using different member functions of the String class. Here is the output when you run the program with the argument “hello” SPELT EXACTLY AS IS (all lowercase).

ignoreCase true: hello
found using compareTo: 32
found using compareToIgnoreCase: 0

Let’s discover why. Here are the descriptions of the member functions:

boolean equals(String another)

The equals() function will take another String as its parameter and check if it is EXACTLY like the initial String. The initial string is what you called the member function from. So in the above program, the initial string is the variable word.

This method reutrns a boolean value. If true, the string parameter is an exact copy of the initial string. If false, the argument is not a copy as something differs in the string.

As noted, the above program returns false when the equals() method is used because of the case difference.

boolean equalsIgnoreCase(String another)

This method is similar to the regular equals() method with the exception of this method not taking into account the case (either upper or lower) of BOTH strings.

So in the program above, this function returns true because of the ignoring of the case. If the keyword above was “HelloA”, this function will return false because they are still different strings.

int compareTo(String another)

This method compares two Strings lexicographically, meaning it will compare the strings in alphabetical order character by character. The method will return a negative number of the differences between the strings, a 0 if they are equal or a positive number representing how much they differ. The negative return means that string comes before the other lexicographically while the positive return means it comes after the other.

So in the above program, the function returns a 32 because of the following reason; when they compare the first characters of both string (initial string = ‘h’ and argument string = ‘H’), they differ by an ASCII value of 32. The function returns 32 to the user. ASCII values are computer codes for different letters and numbers.

int compareToIgnoreCase(String another)

This method preforms the same actions of the regualr compareTo() method but this one will ignore any case difference. The method returns the same values as the compareTo().

Variables

Variables

Variables store data that your code can use.

There are two fundamental categories of variables, primitive data and references:

  • With primitive data, the compiler names a memory location and uses itto store the actual data – numeric values such as integers, floating point values, and the code values of single individual text characters are stored as primitives.
  • With references, the data is accessed indirectly – the compiler selects a memory location, associates it with the variable name, and stores in it a value that is effectively the memory address of the actual data – in Java, all objects and arrays are stored using references.

In the diagram below, the boxes are areas in memory:

Object storage and reference variable

Declaring Variables

Variables must be declared before they are used.

A declaration informs the compiler that you wish to:

  • Create an identifier that will be accepted by the compiler within a section of code (exactly what that section is depends on how and where the variable is declared; that is the concept of scope, which will be addressed later).
  • Associate that identifier with a specified type of data, and enforce restrictions related to that in the remainder of your code.
  • Create a memory location for the specified type of data.
  • Associate the identifier with that memory location.

Java uses many specific data types; each has different properties in terms of size required and handling by the compiler:

  • The declaration specifies the name and datatype.
  • Generally the declaration also defines the variable, meaning that it causes the compiler to allocate storage space in memory of the requested type’s size.
  • A declaration may also assign an initial value (to initialize the variable).
  • Multiple variables of the same type can be declared in a comma-separated list.

Arrays

Array Data Structure

Introduction

An array is an aggregate data structure that is designed to store a group of objects of the same or different types. Arrays can hold primitives as well as references. The array is the most efficient data structure for storing and accessing a sequence of objects.

Here is the list of most important array features you must know (i.e. be able to program)

  • copying and cloning
  • insertion and deletion
  • searching and sorting

You already know that the Java language has only two data types, primitives and references. Which one is an array? Is it primitive? An array is not a primitive data type – it has a field (and only one), called length. Formally speaking, an array is a reference type, though you cannot find such a class in the Java APIs. Therefore, you deal with arrays as you deal with references. One of the major diffeences between refeences and primituives is that you cannot copy arrays by assigning one to another:

int[] a = {9, 5, 4};
int[] b = a;

The assignment operator creates an alias to the object, like in the picture below

 

Since these two references a and b refer to the same object, comparing them with the double equal sign “==” will always return true. In the next code example,

int [] a = {1,2,3};
int [] b = {1,2,3};

a and b refer to two different objects (though with identical contents). Comparing them with the double equal sign will return false. How would you compare two objects with identical contents? In short, using theequals method. For array comparison, the Java APIs provides the Arrays class.

The Arrays class

The java.util.Arrays class is a convenience class for various array manipulations, like comparison, searching, printing, sorting and others. Basically, this class is a set of static methods that are all useful for working with arrays. The code below demonstrates a proper invocation of equals:

int[] a = {1,2,3};
int[] b = {1,2,3};
if( Arrays.equals(a, b) )
   System.out.println("arrays with identical contents");

Another commonly used method is toString() which takes care of of printing

int[] a = {1,2,3};
System.out.println(Arrays.toString(a));

Here is the example of sorting

int[] a = {3,2,1};
Arrays.sort(a);
System.out.println(Arrays.toString(a));

In addition to that, the class has other utility methods for supporting operations over multidimensional arrays.

Copying arrays

There are four ways to copy arrays

  1. using a loop structure
  2. using Arrays.copyOf()
  3. using System.arraycopy()
  4. using clone()

The first way is very well known to you

int[] a = {1, 2, 3};
int[] b = new int[a.length];
for(int i = 0; i ‹ a.length; i++) b[i] = a[i];

The next choice is to use Arrays.copyOf()

int[] a = {1, 2, 3};
int[] b = Arrays.copyOf(a, a.length);

The second parameter specifies the length of the new array, which could either less or equal or bigger than the original length.

The most efficient copying data between arrays is provided by System.arraycopy() method. The method requires five arguments. Here is its signature

public static void arraycopy(Object source,
                             int srcIndex,
                             Object destination,
                             int destIndex,
                             int length)

The method copies length elements from a source array starting with the index srcIndex to a new array destination at the index destIndex.The above code example can be rewritten as it follows

int[] a = {1, 2, 3};
int[] b = new int[a.length];
System.arraycopy(a, 0, b, 0, 3)

And the last copying choice is the use of cloning. Cloning involves creating a new array of the same size and type and copying all the old elements into the new array. The clone() method is defined in the Objectclass and its invocation is demonstrated by this code segment

int[] a = {1, 2, 3};
int[] b = (int[]) a.clone();

Note, that casting (int[]) is the must.

Examine the code in ArrayCopyPrimitives.java for further details.

Insertion and Deletion

Arrays in Java have no methods and only one immutable field length. Once an array is created, its length is fixed and cannot be changed. What do you do to resize the array? You allocate the array with a different size and copy the contents of the old array to the new array. This code example demonstrates deletion from an array of primitives

public char[] delete(char[] data, int pos)
{
	if(pos >= 0 && pos < data.length)
	{
		char[] tmp = new char[data.length-1];
		System.arraycopy(data, 0, tmp, 0, pos);
		System.arraycopy(data, pos+1, tmp, pos, data.length-pos-1);
		return tmp;
	}
	else
		return data;
}

The first arraycopy copies the elements from index 0 to index pos-1, the second arraycopy copies the elements from index pos+1 to data.length.

Examine the code in ArrayDemo.java for further details.

The ArrayList class

The java.util.ArrayList class supports an idea of a dynamic array – an array that grows and shrinks on demand to accomodate the number of elements in the array. Below is a list of commonly used methods

  • add(object) – adds to the end
  • add(index, object) – inserts at the index
  • set(index, object) – replaces at the index
  • get(index) – returns the element at that index
  • remove(index) – deletes the element at that index
  • size() – returns the number of elements

The following code example will give you a heads up into how some of them are used.

/* ADD */
      ArrayList<Integer> num = new ArrayList<Integer>();
      for(int i = 0; i < 10; i++) num.add(i);
      System.out.println(num);

/* REMOVE even integers */
      for(int i = 0; i < num.size(); i++)
      	if(num.get(i)%2 == 0) num.remove(i);
      System.out.println(num);

Copying arrays of objects

This topic is more complex for understanding.. Let us start with a simple loop structure

Object[] obj1 = {new Integer(10),
                new StringBuffer("foobar"),
                new Double(12.95)};
Object[] obj2 = new Object[obj1.length];
for(int i = 0; i ‹ obj1.length; i++)
	obj2[i] = obj1[i];

At the first glance we might think that all data is copied. In reality, the internal data is shared between two arrays. The figure below illustrates the inner structure

The assignment operator obj2[i] = obj1[i] is a crucial part of understanding the concept. You cannot copy references by assigning one to another. The assignment creates an alias rather than a copy. Let us trace down changes in the above picture after execution the following statements

obj1[0] = new Integer(5);

and ((StringBuffer) obj1[1]).append('s');

As you see, obj1[0] and obj2[0] now refer to different objects. However, obj1[1] and obj2[1] refer to the same object (which is “foobars”). Since both arrays shares the data, you must be quite careful when you modify your data, because it might lead to unexpected effects.

The same behavior will take place again, if we use Arrays.copuyOf()System.arraycopy() and clone(). Examine the code example ArrayCopyReferences.java for further details.

Multi-dimensional arrays

In many practical application there is a need to use two- or multi-dimensional arrays. A two-dimensional array can be thought of as a table of rows and columns. This creates a table of 2 rows and 4 columns:

int[][] ar1 = new int[2][4];

You can create and initialize an array by using nested curcly braces. For example, this creates a table of 3 rows and 2 columns:

int[][] ar2 = {{1,2},{3,4},{5,6}};

Generally speaking, a two-dimensional array is not exactly a table – each row in such array can have a different length. Consider this code fragment

Object[][] obj = {{new Integer(1),new Integer(2)},
                  {new Integer(10), "bozo", new Double(1.95)}};

The accompanying picture sheds a bit of light on internal representation

 

From the picture you clearly see that a two-dimensional array in Java is an array of arrays. The array obj has two elements obj[0] and obj[1] that are arrays of length 2 and 3 respectively.

Cloning 2D arrays

The procedure is even more confusing and less expected. Consider the following code segment

Object[][] obj = {{new Integer(1),new Integer(2)},
                  {new Integer(10), "bozo", new Double(1.95)}};

Object[][] twin = (Object[][]) obj.clone();

The procedure of clonig 2d arrays is virtually the same as cloning an array of references. Unfortunately, built-in clone() method does not actualy clone each row, but rather creates references to them Here is a graphical interpretation of the above code

Let us change the value of obj[1][1]

obj[1][1] = "xyz";

This assignment effects the value of twin[1][1] as well

 

Such a copy is called a “shallow” copy. The default behavior of clone() is to return a shallow copy of the object. If we want a “deep” copy instead, we must provide our own implementation by overriding Object’sclone() method.

The idea of a “deep” copy is simple – it makes a distinct copy of each of the object’s fields, recursing through the entire object. A deep copy is thus a completely separate object from the original; changes to it don’t affect the original, and vise versa. In relevance to the above code, here is a deep clone graphically

 

Further, making a complete deep copy is not always needed. Consider an array of immutable objects. As we know, immutable objects cannot be modified, allowing clients to share the same instance without interfering with each other. In this case there is no need to clone them, which leads to the following picture

 

Always in this course we will create data structures of immutable objets, therefore implementing the clone method will require copying a structure (a shape) and sharing its internal data. We will discuss these issues later on in the course.


Victor S.Adamchik, CMU, 2009