Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
CPSC 112 Introduction to Programming Midterm Exam Review Guide Spring 2017 (The current version is the 2016 version, and we will update to 2017 soon.) This guide covers some basic topics. Please be sure to read the lecture slides for additional topics such as program analysis as well. YALE DEPARTMENT OF COMPUTER SCIENCE Table of Contents “Native” Java.................................................................................................................................................... 4 Architecture ................................................................................................................................................. 4 Operators ..................................................................................................................................................... 4 Data Types ................................................................................................................................................... 8 Primitive Data Types ................................................................................................................................ 9 Arrays ..................................................................................................................................................... 10 Printing Output .......................................................................................................................................... 13 Generic Printing ..................................................................................................................................... 13 Formatted Output.................................................................................................................................. 14 Variables .................................................................................................................................................... 16 Local and Global (Class-scope) Variables ............................................................................................... 16 The final Keyword .................................................................................................................................. 16 Program Structure and Control Flow ......................................................................................................... 16 Using Methods ....................................................................................................................................... 16 Declaring Methods................................................................................................................................. 17 Methods with Exceptions ...................................................................................................................... 18 if (...) {…} / else if (…) {…} / else{ … } Statement ..................................................................................... 19 switch (…) {…} Statement ....................................................................................................................... 20 for (…; …; …) {…} Statement ................................................................................................................... 21 while (…) {…} Statement ........................................................................................................................ 23 do { … }while (…) Statement .................................................................................................................. 24 Loop Types ............................................................................................................................................. 24 Fencepost Loops .................................................................................................................................... 25 Program Analysis ................................................................................................................................... 25 Standard Java Classes .................................................................................................................................... 26 String .......................................................................................................................................................... 26 Regular expressions ................................................................................................................................... 29 Scanner ...................................................................................................................................................... 29 Math........................................................................................................................................................... 32 Graphics using StdDraw ............................................................................................................................. 33 Color........................................................................................................................................................... 33 Much of the material contained in this review guide is included from the Java Platform API (“Javadocs”) and The Java Tutorials. Please see these websites for further details about the Java programming language as presented herein. “Native” Java We are taking artistic license in referring to “native” Java and if you do a Google search on this term, you will probably not find anything that satisfactorily indicates what this means. Think of this phrase as a reference to those features that are built-in to Java and that are not represented as standalone classes or interfaces in the Jave framework / Java Development Kit (JDK). It is relevant to tackle these aspects of the language – including operators, primitive data types, conditional statements, and loops – separately from some of the “higher-levels” parts of the Java platform in order to build a clear foundation of the language’s underpinnings and to distinguish simple aspects of Java from more complicated things that are implemented by grouping these simple operations together. While the general overviews given should be sufficient to understand what these programming conventions do and how they can be used, refer to your textbook as needed to lookup additional information about any of the items discussed. Architecture Java is an architecture-neutral language, meaning that source code compiled into “bytecode” for use on one platform can be used on any other that has the Java Runtime Environment (JRE) installed. While integrated development environments (“IDE”’s) such as Eclipse, Dr. Java, and many others can be used to automate the processes for compiling and running Java programs, take note of the following applications included with the Java Development Kit (JDK) that are instrumental to building and using Java programs: java – runs a .class file (which represents a Java application as Java bytecode) via the Java Runtime Environment (JRE) javac – compiles Java source code (.java files) into Java bytecode (.class files) jar – utility for compressing multiple files (e.g., .class, .txt, .java, etc.) into a single .jar file; .class files within a .jar file can be executed without having to decompress the .jar file in which they are stored Operators The Simple Assignment Operator One of the most common operators that you'll encounter is the simple assignment operator "=". It assigns the value on its right to the operand on its left: int cadence = 0; int speed = 0; int gear = 1; This operator can also be used on objects to assign object references. The Arithmetic Operators The Java programming language provides operators that perform addition, subtraction, multiplication, division, and reminder. There's a good chance you'll recognize them by their counterparts in basic mathematics. The only symbol that might look new to you is "%", which divides one operand by another and returns the remainder as its result. + * / % additive operator (also used for String concatenation) subtraction operator multiplication operator division operator remainder operator All of these operators follow the basic order-of-operations common to arithmetic. Additionally, note that parentheses may be used to change (or emphasize) the order in which these operations occur. The following program, ArithmeticDemo, tests the arithmetic operators. public class ArithmeticDemo { public static void main (String[] args){ int result = 1 + 2; // result is now 3 System.out.println(result); result = result - 1; // result is now 2 System.out.println(result); result = result * 2; // result is now 4 System.out.println(result); result = result / 2; // result is now 2 System.out.println(result); result = result + 8; // result is now 10 result = result % 7; // result is now 3 System.out.println(result); } } You can also combine the arithmetic operators with the simple assignment operator to create compound assignments. For example, x+=1; and x=x+1; both increment the value of x by 1. The + operator can also be used for concatenating (joining) two strings together, as shown in the following ConcatDemo program: public class ConcatDemo { public static void main(String[] args){ String firstString = "This is"; String secondString = " a concatenated string."; String thirdString = firstString+secondString; System.out.println(thirdString); } } By the end of this program, the variable thirdString contains "This is a concatenated string.", which gets printed to standard output. The Unary Operators The unary operators require only one operand; they perform various operations such as incrementing/decrementing a value by one, negating an expression, or inverting the value of a boolean. + ++ -! Unary plus operator; indicates positive value (numbers are positive without this, however) Unary minus operator; negates an expression Increment operator; increments a value by 1 Decrement operator; decrements a value by 1 Logical complement operator; inverts the value of a boolean The following program, UnaryDemo, tests the unary operators: public class UnaryDemo { public static void main(String[] args){ int result = +1; // result is now 1 System.out.println(result); result--; // result is now 0 System.out.println(result); result++; // result is now 1 System.out.println(result); result = -result; // result is now -1 System.out.println(result); boolean success = false; System.out.println(success); // false System.out.println(!success); // true } } The increment/decrement operators can be applied before (prefix) or after (postfix) the operand. The code result++; and ++result; will both end in result being incremented by one. The only difference is that the prefix version (++result) evaluates to the incremented value, whereas the postfix version (result++) evaluates to the original value. If you are just performing a simple increment/decrement, it doesn't really matter which version you choose. But if you use this operator in part of a larger expression, the one that you choose may make a significant difference. The following program, PrePostDemo, illustrates the prefix/postfix unary increment operator: public class PrePostDemo { public static void main(String[] args){ int i = 3; i++; System.out.println(i); // "4" ++i; System.out.println(i); // "5" System.out.println(++i); // "6" System.out.println(i++); // "6" System.out.println(i); // "7" } } The Equality and Relational Operators The equality and relational operators determine if one operand is greater than, less than, equal to, or not equal to another operand. The majority of these operators will probably look familiar to you as well. Keep in mind that you must use "==", not "=", when testing if two primitive values are equal. == != > >= < <= equal to not equal to greater than greater than or equal to less than less than or equal to The following program, ComparisonDemo, tests the comparison operators: public class ComparisonDemo { public static void main(String[] args){ int value1 = 1; int value2 = 2; if(value1 == value2) System.out.println("value1 == value2"); if(value1 != value2) System.out.println("value1 != value2"); if(value1 > value2) System.out.println("value1 > value2"); if(value1 < value2) System.out.println("value1 < value2"); if(value1 <= value2) System.out.println("value1 <= value2"); } } Output: value1 != value2 value1 < value2 value1 <= value2 The Conditional Operators The && and || operators perform Conditional-AND and Conditional-OR operations on two boolean expressions. These operators exhibit "short-circuiting" behavior, which means that the second operand is evaluated only if needed. && Conditional-AND || Conditional-OR The following program, ConditionalDemo1, tests these operators: public class ConditionalDemo1 { public static void main(String[] args){ int value1 = 1; int value2 = 2; if((value1 == 1) && (value2 == 2)) System.out.println("value1 is 1 AND value2 is 2"); if((value1 == 1) || (value2 == 1)) System.out.println("value1 is 1 OR value2 is 1"); } } Summary of Operator Precedence As a summarize, the precedence of all operators in Java is the following: Arithmetic operators Relations operators (==, !=, <, >, <=, >=) NOT (!) AND (&&) OR (||) Assignment operators (=) Data Types The Java programming language is statically-typed, which means that all variables must first be declared before they can be used. This involves stating the variable's type and name, as you've already seen: int gear = 1; Doing so tells your program that a field named "gear" exists, holds numerical data, and has an initial value of "1". A variable's data type determines the values it may contain, plus the operations that may be performed on it. Primitive Data Types A primitive type is predefined by the language and is named by a reserved keyword. Primitive values do not share state with other primitive values. In addition to int, the Java programming language supports seven other primitive data types. Some primitive data types supported by the Java programming language are: int: The int data type is a 32-bit signed two's complement integer. It has a minimum value of - 2,147,483,648 and a maximum value of 2,147,483,647 (inclusive). For integral values, this data type is generally the default choice unless there is a reason (like the above) to choose something else. This data type will most likely be large enough for the numbers your program will use, but if you need a wider range of values, use long instead. double: The double data type is a double-precision 64-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in section 4.2.3 of the Java Language Specification. For decimal values, this data type is generally the default choice. As mentioned above, this data type should never be used for precise values, such as currency. boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its "size" isn't something that's precisely defined. char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive). In addition to the primitive data types listed above, the Java programming language also provides special support for character strings via the java.lang.String class. Enclosing your character string within double quotes will automatically create a new String object; for example, String s = "this is a string";. String objects are immutable, which means that once created, their values cannot be changed. The String class is not technically a primitive data type, but considering the special support given to it by the language, you'll probably tend to think of it as such. When using int and double data types together in common expressions, you are strongly encouraged to type cast variables as you intend, even when this may be done automatically by the Java Runtime Environment. Doing so enhances readability while helping ensure that your program operates as desired. To type cast a variable and/or value, simply encapsulate the data type you wish to use in parentheses, and include this notation in advance of where the variable/value appears. Consider the following example: double answer = (double)4 / (double)10; This will cause the value 0.4 to be placed within answer. Note that had type casting not been used in this example, the value 0.0 would have been stored in answer instead since Java would have performed integer division, resulting in down-rounding to the nearest whole number (0). Arrays An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. After creation, its length is fixed. You've seen an example of arrays already, in the main method of the "Hello World!" application. This section discusses arrays in greater detail. Each item in an array is called an element, and each element is accessed by its numerical index. As shown in the above illustration, numbering begins with 0. The 9th element, for example, would therefore be accessed at index 8. The following program, ArrayDemo, creates an array of integers, puts some values in it, and prints each value to standard output. class ArrayDemo { public static void main(String[] args) { int[] anArray; // declares an array of integers anArray = new int[10]; // allocates memory for 10 integers anArray[0] = 100; // initialize first element anArray[1] = 200; // initialize second element anArray[2] = 300; // etc. anArray[3] = 400; anArray[4] = 500; anArray[5] = 600; anArray[6] anArray[7] anArray[8] anArray[9] = = = = 700; 800; 900; 1000; System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element System.out.println("Element at at at at at at at at at at index index index index index index index index index index 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: " " " " " " " " " " + + + + + + + + + + anArray[0]); anArray[1]); anArray[2]); anArray[3]); anArray[4]); anArray[5]); anArray[6]); anArray[7]); anArray[8]); anArray[9]); } } The output from this program is: Element Element Element Element Element Element Element Element Element Element at at at at at at at at at at index index index index index index index index index index 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 100 200 300 400 500 600 700 800 900 1000 In a real-world programming situation, you'd probably use one of the supported looping constructs to iterate through each element of the array, rather than write each line individually as shown above. However, this example clearly illustrates the array syntax. Declaring a Variable to Refer to an Array The above program declares anArray with the following line of code: int[] anArray; // declares an array of integers Like declarations for variables of other types, an array declaration has two components: the array's type and the array's name. An array's type is written as type[], where type is the data type of the contained elements; the square brackets are special symbols indicating that this variable holds an array. The size of the array is not part of its type (which is why the brackets are empty). An array's name can be anything you want, provided that it follows the rules and conventions for naming variables in Java. As with variables of other types, the declaration does not actually create an array — it simply tells the compiler that this variable will hold an array of the specified type. Similarly, you can declare arrays of other types: double[] anArrayOfDoubles; boolean[] anArrayOfBooleans; char[] anArrayOfChars; String[] anArrayOfStrings; You can also place the square brackets after the array's name: double anArrayOfDoubles[]; Creating, Initializing, and Accessing an Array One way to create an array is with the new operator. The next statement in the preceding ArrayDemo program allocates an array with enough memory for ten integer elements and assigns the array to the anArray variable. anArray = new int[10]; // create an array of integers If this statement were missing, the compiler would print an error like the following, and compilation would fail: ArrayDemo.java:4: Variable anArray may not have been initialized. The next few lines assign values to each element of the array: anArray[0] = 100; // initialize first element anArray[1] = 200; // initialize second element anArray[2] = 300; // etc. Each array element is accessed by its numerical index: System.out.println("Element 1 at index 0: " + anArray[0]); System.out.println("Element 2 at index 1: " + anArray[1]); System.out.println("Element 3 at index 2: " + anArray[2]); Alternatively, you can use the shortcut syntax to create and initialize an array: int[] anArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}; Here the length of the array is determined by the number of values provided between { and }. You can also declare an array of arrays (also known as a multidimensional array) by using two or more sets of square brackets, such as String[][] names. Each element, therefore, must be accessed by a Page 12 corresponding number of index values. In the Java programming language, a multidimensional array is simply an array whose components are themselves arrays. This is unlike arrays in C or Fortran. A consequence of this is that the rows are allowed to vary in length, as shown in the following MultiDimArrayDemo program: class MultiDimArrayDemo { public static void main(String[] args) { String[][] names = {{"Mr. ", "Mrs. ", "Ms. "}, {"Smith", "Jones"}}; System.out.println(names[0][0] + names[1][0]); //Mr. Smith System.out.println(names[0][2] + names[1][1]); //Ms. Jones } } The output from this program is: Mr. Smith Ms. Jones Finally, you can use the built-in length property to determine the size of any array. The code System.out.println(anArray.length); will print the array's size to standard output. Printing Output Generic Printing Invoking System.out.print or System.out.println outputs a single value after converting the value to a String, if necessary. Note that System.out.print outputs a value without giving it its own line, whereas System.out.println adds a newline after printing the parameter passed. We can see this in the example below: public class Root{ public static void main(String[] args) { int i = 2; double r = Math.sqrt(i); System.out.print("The square root of "); System.out.print(i); System.out.print(" is "); System.out.print(r); System.out.println("."); i = 5; r = Math.sqrt(i); System.out.println("The square root of " + i + " is " + r + "."); } } Here is the output: Page 13 The square root of 2 is 1.4142135623730951. The square root of 5 is 2.23606797749979. In one case, the variables i and r are printed directly in standalone calls to print(); in another case, these variables are concatenated into a String and then printed with the rest of the String’s contents. While either approach is acceptable, note that the latter is more succinct. Formatted Output Java introduces formatting string that is used by System.out.printf and String.format. The difference between printf and format is that the former prints to the output, while the later generates a String that you can print later. We use printf as example. You can use printf anywhere in your code where you have otherwise been using print or println. For example, System.out.printf(.....); The syntax for printf is as follows: public PrintStream printf(String format, Object... args) where format is a string that specifies the formatting to be used and args is a list of the variables to be printed using that formatting. A simple example would be System.out.printf("The value of the float variable is %f, while the " + "value of the integer variable is %d, and " + "the string is %s", floatVar, intVar, stringVar); The first parameter, format, is a format string specifying how the objects in the second parameter, args, are to be formatted. The format string contains plain text as well as format specifiers, which are special characters that format the arguments of Object... args. (The notation Object... args is called varargs, which means that the number of arguments may vary.) Format specifiers begin with a percent sign (%) and end with a converter. The converter is a character indicating the type of argument to be formatted. In between the percent sign (%) and the converter you can have optional flags and specifiers. There are many converters, flags, and specifiers, which are documented Here is a basic example: int i = 461012; System.out.printf("The value of i is: %d%n", i); The %d specifies that the single variable is a decimal integer. The %n is a platform-independent newline character. The output is: Page 14 The value of i is: 461012 The below table lists some of the converters and flags that are commonly used in conjunction with printf. Converter Flag Explanation d A decimal integer. f A float. n A new line character appropriate to the platform running the application. This is generally interchangeable with \n. 08 Eight characters in width, with leading zeroes as necessary. + Includes sign, whether positive or negative. , Includes locale-specific grouping characters. - Left-justified. .3 Three places after decimal point. 10.3 Ten characters in width, right justified, with three places after decimal point. The following program shows some of the formatting that you can do with format based on the converters noted above. The output is shown within double quotes in the embedded comment: public class TestPrint { public static void main(String[] args) { long n = 461012; System.out.printf("%d%n", n); System.out.printf("%08d%n", n); System.out.printf("%+8d%n", n); System.out.printf("%,8d%n", n); System.out.printf("%+,8d%n%n", n); double pi = Math.PI; System.out.printf("%f%n", pi); System.out.printf("%.3f%n", pi); System.out.printf("%10.3f%n", pi); System.out.printf("%-10.3f%n", pi); } } Page 15 // // // // // --> --> --> --> --> "461012" "00461012" " +461012" " 461,012" "+461,012" // // // // --> --> --> --> "3.141593" "3.142" " 3.142" "3.142" Note that when using %.xf (where x indicates a desired number of digits to display to the right of a decimal point when printing a double or float value), the least significant digit is rounded up or down based on any additional digits that are truncated. Variables Local and Global (Class-scope) Variables Generally, variables are local to the context in which they appear, whether within a nested statement, a method, or even an entire class. In the last of these examples, however, it is usually said that a variable is global because it can be accessed across multiple methods without being passed as a parameter (see the discussion on methods, below). When defining a variable directly inside a class rather than within a method, be sure to include the static keyword with the definition. This in effect “globalizes” the variable and has additional implications that will be discussed later in the course. The final Keyword The static modifier, in combination with the final modifier, is also used to define constants. The final modifier indicates that the value of this field cannot change. For example, the following variable declaration defines a constant named PI, whose value is an approximation of pi (the ratio of the circumference of a circle to its diameter): static final double PI = 3.141592653589793; Constants defined in this way cannot be reassigned, and it is a compile-time error if your program tries to do so. By convention, the names of constant values are spelled in uppercase letters. If the name is composed of more than one word, the words are separated by an underscore (_). Program Structure and Control Flow Using Methods Methods contain sets of Java statements that can be invoked using a single method “call.” These structures can both accept input and can create output, though may not necessarily do either. A typical method call is the following: double result = calculateAnswer(51.2, numEngines, length, grossTons); In this case, the method is named calculateAnswer, and a combination of values (51.2) and variables (numEngines, length, and grossTons) are passed as parameters. The return value generated by calculateAnswer is placed within result. In addition to custom methods that Page 16 programmers may create, note that Java includes a wealth of functionality that is built-in. See the section on “Standard Java Classes” for more information. Declaring Methods Here is an example of a typical method declaration: public static double calculateAnswer(double wingSpan, int numberOfEngines, double length, double grossTons) { //do the calculation here } The only required elements of a method declaration are the method's return type, name, a pair of parentheses, (), and a body between braces, {}. More generally, method declarations have six components, in order: 1. Modifiers—such as public, private, static, and others you will learn about later. 2. The return type—the data type of the value returned by the method, or void if the method does not return a value. 3. The method name. 4. The parameter list in parenthesis—a comma-delimited list of input parameters, preceded by their data types, enclosed by parentheses, (). If there are no parameters, you must use empty parentheses. 5. The method body, enclosed between braces—the method's code, including the declaration of local variables, goes here. The Java programming language supports overloading methods, and Java can distinguish between methods with different method signatures. This means that methods within a class can have the same name if they have different parameter lists (there are some qualifications to this that will be discussed in the lesson titled "Interfaces and Inheritance"). Suppose that you have a class that can use calligraphy to draw various types of data (strings, integers, and so on) and that contains a method for drawing each data type. It is cumbersome to use a new name for each method—for example, drawString, drawInteger, drawFloat, and so on. In the Java programming language, you can use the same name for all the drawing methods but pass a different argument list to each method. Thus, the data drawing class might declare four methods named draw, each of which has a different parameter list. public class DataArtist { ... public static void draw(String s) { ... } public static void draw(int i) { ... } Page 17 public static void draw(double f) { ... } public static void draw(int i, double f) { ... } } Overloaded methods are differentiated by the number and the type of the arguments passed into the method. In the code sample, draw(String s) and draw(int i) are distinct and unique methods because they require different argument types. You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart. The compiler does not consider return type when differentiating methods, so you cannot declare two methods with the same signature even if they have a different return type. Methods with Exceptions Technically, an exception is an object representing a runtime error. But this does not say much. The main motivation when programming languages introduced exceptions is to allow a method to signal to its invoker that an error has occurred instead of having to return a special return value to signal the error. Consider the Integer.parseInt method that takes a string and returns an integer. If the input string is not a valid number, which value to return to signal the error? For such cases, throwing an exception is a more uniform approach. Certain methods (e.g., Scanner(File source)) require that the invoker must handle exceptions (i.e. checked exceptions). There are two approaches to handle exceptions. o Could handle exception with a throw clause in the invoking method’s header, with syntax: o public static <type> <name>(…) throws <type> Essentially an acknowledgement that you realize the method could throw an exception; passes the duty of handling the checked exception to the method that invoked it. o Could handle exception with a try/catch statement o The important thing to remember with a try/catch statement is that code is executed normally until an exception is triggered (if one is triggered at all). At this point (if it occurs), code within the try statement ceases execution and the catch statement for the appropriate exception begins execution. Page 18 if (...) {…} / else if (…) {…} / else{ … } Statement The if-then statement is the most basic of all the control flow statements. It tells your program to execute a certain section of code only if a particular test evaluates to true. For example, consider a method that would adjust the speed of a (virtual) bicycle given a Boolean variable indicating whether the bike is in motion: void applyBrakes(){ if (isMoving){ // the "if" clause: bicycle must be moving currentSpeed--; // the "then" clause: decrease current speed } } If this test evaluates to false (meaning that the bicycle is not in motion), control jumps to the end of the if-then statement. In addition, the opening and closing braces are optional, provided that the "then" clause contains only one statement: void applyBrakes(){ if (isMoving) currentSpeed--; // same as above, but w/o braces } Deciding when to omit the braces is a matter of personal taste. Omitting them can make the code more brittle. If a second statement is later added to the "then" clause, a common mistake would be forgetting to add the newly required braces. The compiler cannot catch this sort of error; you'll just get the wrong results. The if-then-else statement provides a secondary path of execution when an "if" clause evaluates to false. You could use an if-then-else statement in the applyBrakes method to take some action if the brakes are applied when the bicycle is not in motion. In this case, the action is to simply print an error message stating that the bicycle has already stopped. void applyBrakes(){ if (isMoving) { currentSpeed--; } else { System.err.println("The bicycle has already stopped!"); } } The following program, IfElseDemo, assigns a grade based on the value of a test score: an A for a score of 90% or above, a B for a score of 80% or above, and so on. public class IfElseDemo { public static void main(String[] args) { Page 19 int testscore = 76; char grade; if (testscore >= 90) { grade = 'A'; } else if (testscore >= 80) grade = 'B'; } else if (testscore >= 70) grade = 'C'; } else if (testscore >= 60) grade = 'D'; } else { grade = 'F'; } System.out.println("Grade = { { { " + grade); } } The output from the program is: Grade = C You may have noticed that the value of testscore can satisfy more than one expression in the compound statement: 76 >= 70 and 76 >= 60. However, once a condition is satisfied, the appropriate statements are executed (grade = 'C';) and the remaining conditions are not evaluated. By the same token, once you have determined a certain condition to be true (e.g., through the use of an if statement), the typically remains true in subsequent lines. This ability to make an assumption based on prior analysis is formally known as assertion. switch (…) {…} Statement Unlike if-then and if-then-else statements, the switch statement can have a number of possible execution paths. A switch works with the char and int primitive data types; it also works with the String class. The following code example, SwitchDemo, declares an int named month whose value represents a month. The code displays the name of the month, based on the value of month, using the switch statement. public class SwitchDemo { public static void main(String[] args) { int month = 8; String monthString; switch (month) { case 1: monthString = "January"; case 2: monthString = "February"; Page 20 break; break; case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: default: monthString monthString monthString monthString monthString monthString monthString monthString monthString monthString monthString = = = = = = = = = = = "March"; "April"; "May"; "June"; "July"; "August"; "September"; "October"; "November"; "December"; "Invalid month"; break; break; break; break; break; break; break; break; break; break; break; } System.out.println(monthString); } } In this case, August is printed to standard output. The body of a switch statement is known as a switch block. A statement in the switch block can be labeled with one or more case or default labels. The switch statement evaluates its expression, then executes all statements that follow the matching case label. You could also display the name of the month with if-then-else statements: int month = 8; if (month == 1) { System.out.println("January"); } else if (month == 2) { System.out.println("February"); } . . . // and so on Deciding whether to use if-then-else statements or a switch statement is based on readability and the expression that the statement is testing. An if-then-else statement can test expressions based on ranges of values or conditions, whereas a switch statement tests expressions based only on a single numeric or String value. Another point of interest is the break statement. Each break statement terminates the enclosing switch statement. Control flow continues with the first statement following the switch block. The break statements are necessary because without them, statements in switch blocks fall through: All statements after the matching case label are executed in sequence, regardless of the expression of subsequent case labels, until a break statement is encountered. Furthermore, note that a default section handles all values that are not explicitly handled by one of the case sections. for (…; …; …) {…} Statement The for statement provides a compact way to iterate over a range of values. Programmers often refer to it as the "for loop" because of the way in which it repeatedly loops until a particular condition is satisfied. The general form of the for statement can be expressed as follows: Page 21 for (initialization; termination test; increment) { statement(s) } When using this version of the for statement, keep in mind that: The initialization expression initializes the loop; it's executed once, as the loop begins. When the termination test expression evaluates to false, the loop terminates. The increment expression is invoked after each iteration through the loop; it is perfectly acceptable for this expression to increment or decrement a value. The following program, ForDemo, uses the general form of the for statement to print the numbers 1 through 10 to standard output: public class ForDemo { public static void main(String[] args){ for(int i=1; i<11; i++){ System.out.println("Count is: " + i); } } } The output of this program is: Count Count Count Count Count Count Count Count Count Count is: is: is: is: is: is: is: is: is: is: 1 2 3 4 5 6 7 8 9 10 Notice how the code declares a variable within the initialization expression. The scope of this variable extends from its declaration to the end of the block governed by the for statement, so it can be used in the termination and increment expressions as well. If the variable that controls a for statement is not needed outside of the loop, it's best to declare the variable in the initialization expression. The names i, j, and k are often used to control for loops; declaring them within the initialization expression limits their life span and reduces errors. As a final note about for and while loops, observe the availability of the break statement. You can use break to terminate a for or while loop, as shown in the following BreakDemo program: public class BreakDemo { public static void main(String[] args) { Page 22 int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076, 2000, 8, 622, 127 }; int searchfor = 12; int i; boolean foundIt = false; for (i = 0; i < arrayOfInts.length; i++) { if (arrayOfInts[i] == searchfor) { foundIt = true; break; } } if (foundIt) { System.out.println("Found " + searchfor + " at index " + i); } else { System.out.println(searchfor + " not in the array"); } } } This program searches for the number 12 in an array. The break statement, shown in boldface, terminates the for loop when that value is found. Control flow then transfers to the print statement at the end of the program. This program's output is: Found 12 at index 4 while (…) {…} Statement The while statement continually executes a block of statements while a particular condition is true. Its syntax can be expressed as: while (expression) { statement(s) } The while statement evaluates expression, which must return a boolean value. If the expression evaluates to true, the while statement executes the statement(s) in the while block. The while statement continues testing the expression and executing its block until the expression evaluates to false. Using the while statement to print the values from 1 through 10 can be accomplished as in the following WhileDemo program: public class WhileDemo { public static void main(String[] args){ Page 23 int count = 1; while (count < 11) { System.out.println("Count is: " + count); count++; } } } You can implement an infinite loop using the while statement as follows: while (true){ // your code goes here } do { … }while (…) Statement The Java programming language also provides a do-while statement, which can be expressed as follows: do { statement(s) } while (expression); The difference between do-while and while is that do-while evaluates its expression at the bottom of the loop instead of the top. Therefore, the statements within the do block are always executed at least once, as shown in the following DoWhileDemo program: class DoWhileDemo { public static void main(String[] args){ int count = 1; do { System.out.println("Count is: " + count); count++; } while (count <= 11); } } Loop Types Loops created using either for or while can exist in a number of forms; the most common of these are summarized below: Continuous Loops – iterate ad infinitum, and commonly an unintended programming error Early Exit Loops – through the use of the break keyword, some loops can be “stopped early” Sentinel Loops – these are the most traditional loops which continue iterating until a particular condition (i.e., the termination test) tested on each iteration is no longer true Page 24 Additionally, be on the lookout for so-called “fencepost” or “off-by-one” issues when using loops. These are common sources of errors where mistaken interpretation of exactly how many times a loop should iterate causes a loop to execute one time more or less than intended. Be sure to double-check your test condition to be sure that it causes the proper number of iterations to occur. Fencepost Loops Fencepost is a general term in computer science when you alternate between two operations but begin and end with the same operation. In class we made the Fence Post Analogy: If consecutive fence posts are connected by wire, then you will have one more fence post than connecting wire when you finish building your fence. It is important to recognize fence post situations in your programs because in those situations the extra fence post will often have to be handled before or after the loop structure used. place a post loop(length of fence – 1 number of times) place wire place post A slightly less efficient method for handling a fence post problem is to check within the loop if you are on the first or last fence post and to handle that case differently Program Analysis Program analysis is a method of analyzing whether certain requirements (definitive statements about a program at given points in execution) are satisfied. The foundation of program analysis is assertions, where an assertion is a statement made about the state of a program at a given point that could always be true, always be false, or true/false depending on certain initial conditions In particular, assertions can be made around control statements. For example if a while loop has as its test condition x < 0, then you know that at the point the while loop is entered x is negative and at the moment the while loop is exited, x is nonnegative, if there is no break inside the loop. Program requirements often use Iff, which is a stronger statement than if. Iff A happens, then B happens is equivalent to saying if A happens, then B happens and if B happens, then A happens. Page 25 One example of an application of using iff statements to describe execution of a program is iff the user doesn’t input an integer, then an error message is printed. If you know that one of the two conditions is true (either the user didn’t input an integer or an error message was printed), then you know the other condition must have been true as well. Standard Java Classes This section offers a comprehensive review of relevant methods available within Java framework classes that have been covered in this course. This information is in large part based on documentation available through the Java Platform API (“Javadocs”) on the Java website. Additional information about these classes and methods may be obtained by reviewing the Javadocs at the following URL: http://java.sun.com/javase/6/docs/api/ You may also consult your textbook for more extensive examples demonstrating how these classes and methods can be used. String The String class represents character strings. All string literals in Java programs, such as "abc", are implemented as instances of this class. Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example: String str = "abc"; is equivalent to: char data[] = {'a', 'b', 'c'}; String str = new String(data); Here are some more examples of how strings can be used: System.out.println("abc"); String cde = "cde"; System.out.println("abc" + cde); String c = "abc".substring(2,3); String d = cde.substring(1, 2); String Class Methods public String() Page 26 Initializes a newly created String object so that it represents an empty character sequence. Note that use of this constructor is unnecessary since Strings are immutable. public String(String original) Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable. Parameters: original - a String. public char charAt(int index) Returns the char value at the specified index. An index ranges from 0 to length() - 1. The first char value of the sequence is at index 0, the next at index 1, and so on, as for array indexing. If the char value specified by the index is a surrogate, the surrogate value is returned. Parameters: index - the index of the char value. Returns: the char value at the specified index of this string. The first char value is at index 0. public int compareTo(String anotherString) Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argument string. The result is a negative integer if this String object lexicographically precedes the argument string. The result is a positive integer if this String object lexicographically follows the argument string. The result is zero if the strings are equal; compareTo returns 0 exactly when the equals(Object) method would return true. Parameters: anotherString - the String to be compared. Returns: the value 0 if the argument string is equal to this string; a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument. public boolean equals(Object anObject) Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object. Parameters: anObject - the object to compare this String against. Returns: true if the String are equal; false otherwise. public boolean equalsIgnoreCase(String anotherString) Compares this String to another String, ignoring case considerations. Two strings are considered equal ignoring case if they are of the same length, and corresponding characters in the two strings are equal ignoring case. Page 27 Parameters: anotherString - the String to compare this String against. Returns: true if the argument is not null and the Strings are equal, ignoring case; false otherwise. public int indexOf(int ch) Returns the index within this string of the first occurrence of the specified character. Parameters: ch - a character (Unicode code point). Returns: the index of the first occurrence of the character in the character sequence represented by this object, or -1 if the character does not occur. public int indexOf(int ch, int fromIndex) Returns the index within this string of the first occurrence of the specified character, starting the search at the specified index. Parameters: ch - a character (Unicode code point). fromIndex - the index to start the search from. Returns: the index of the first occurrence of the character in the character sequence represented by this object that is greater than or equal to fromIndex, or -1 if the character does not occur. public int indexOf(String str) Returns the index within this string of the first occurrence of the specified substring. Parameters: str - any string. Returns: if the string argument occurs as a substring within this object, then the index of the first character of the first such substring is returned; if it does not occur as a substring, -1 is returned. public int indexOf(String str, int fromIndex) Returns the index within this string of the first occurrence of the specified substring, starting at the specified index. If no such value of k exists, then -1 is returned. Parameters: str - the substring for which to search. fromIndex - the index from which to start the search. Returns: the index within this string of the first occurrence of the specified substring, starting at the specified index. public int length() Returns the length of this string. The length is equal to the number of 16-bit Unicode characters in the string. Returns: the length of the sequence of characters represented by this object. Page 28 public String substring(int beginIndex, int endIndex) Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex. Examples: "hamburger".substring(4, 8) returns "urge" "smiles".substring(1, 5) returns "mile" Parameters: beginIndex - the beginning index, inclusive. endIndex - the ending index, exclusive. Returns: the specified substring. public String toLowerCase() Converts all of the characters in this String to lower case using the rules of the default locale. Returns: the String, converted to lowercase. public String toUpperCase() Converts all of the characters in this String to upper case using the rules of the default locale. Returns: the String, converted to uppercase. Regular expressions A regular expression is a string that defines a search pattern for strings. Regular expressions are a very powerful tool that we use to search, edit, and manipulate text. See lecture 13 for definitions and examples of regular expressions. A good tutorial on regular expressions is http://www.vogella.com/tutorials/JavaRegularExpressions/article.html Scanner A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace. The resulting tokens may then be converted into values of different types using the various next methods. For example, this code allows a user to read a number from System.in: Scanner sc = new Scanner(System.in); int i = sc.nextInt(); The scanner can also use delimiters other than whitespace. This example reads several items in from a string: String input = "1 fish 2 fish red fish blue fish"; Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*"); System.out.println(s.nextInt()); Page 29 System.out.println(s.nextInt()); System.out.println(s.next()); System.out.println(s.next()); s.close(); prints the following output: 1 2 red blue The next() and hasNext() methods and their primitive-type companion methods (such as nextInt() and hasNextInt()) first skip any input that matches the delimiter pattern, and then attempt to return the next token. Both hasNext and next methods may block waiting for further input. Whether a hasNext method blocks has no connection to whether or not its associated next method will block. In this example, \\s*fish\\s* is a regular expression, where \s represents a white space character, and * means it matches from 0 to many white space characters. We write \\s because Java takes \ as a special character. The same output can be generated with the code below, which uses a regular expression to parse all four tokens at once: String input = "1 fish 2 fish red fish blue fish"; Scanner s = new Scanner(input); s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)"); MatchResult result = s.match(); for (int i=1; i<=result.groupCount(); i++) System.out.println(result.group(i); s.close(); Scanner Class Methods public Scanner(InputStream source) Constructs a new Scanner that produces values scanned from the specified input stream. Parameters: source - An input stream to be scanned public Scanner(String source) Constructs a new Scanner that produces values scanned from the specified string. Parameters: source - A string to scan public boolean hasNext() Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input. Page 30 Returns: true if and only if this scanner has another token public boolean hasNextDouble() Returns true if the next token in this scanner's input can be interpreted as a double value using the nextDouble() method. The scanner does not advance past any input. Returns: true if and only if this scanner's next token is a valid double value public boolean hasNextInt() Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the nextInt() method. The scanner does not advance past any input. Returns: true if and only if this scanner's next token is a valid int value public boolean hasNextLine() Returns true if there is another line in the input of this scanner. This method may block while waiting for input. The scanner does not advance past any input. Returns: true if and only if this scanner has another line of input public String next() Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern. This method may block while waiting for input to scan, even if a previous invocation of hasNext() returned true. Returns: the next token public double nextDouble() Scans the next token of the input as a double. This method will throw InputMismatchException if the next token cannot be translated into a valid double value. If the translation is successful, the scanner advances past the input that matched. Returns: the double scanned from the input public int nextInt() Scans the next token of the input as an int. An invocation of this method of the form nextInt() behaves in exactly the same way as the invocation nextInt(radix), where radix is the default radix of this scanner. Returns: the int scanned from the input public String nextLine() Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line. Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present. Returns: Page 31 the line that was skipped Math The class Math contains methods for performing basic numeric operations such as the elementary exponential, logarithm, square root, and trigonometric functions. Math Class Methods public static int abs(int a) public static double abs(double a) public static float abs(float a) Returns the absolute value of the parameter specified. If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned. Special cases: If the argument is positive zero or negative zero, the result is positive zero. If the argument is infinite, the result is positive infinity. If the argument is NaN, the result is NaN. Parameters: a - the argument whose absolute value is to be determined Returns: the absolute value of the argument. public static int max(int a, int b) public static double max(double a, double b) public static float max(float a, float b) Returns the greater of two double values. That is, the result is the argument closer to positive infinity. If the arguments have the same value, the result is that same value. If either value is NaN, then the result is NaN. Unlike the the numerical comparison operators, this method considers negative zero to be strictly smaller than positive zero. If one argument is positive zero and the other negative zero, the result is positive zero. Parameters: a - an argument. b - another argument. Returns: the larger of a and b. public static int min(int a, int b) public static double min(double a, double b) public static float min(float a, float b) Returns the smaller of two double values. That is, the result is the value closer to negative infinity. If the arguments have the same value, the result is that same value. If either value is Page 32 NaN, then the result is NaN. Unlike the the numerical comparison operators, this method considers negative zero to be strictly smaller than positive zero. If one argument is positive zero and the other is negative zero, the result is negative zero. Parameters: a - an argument. b - another argument. Returns: the smaller of a and b. public static double pow(double a, double b) Returns the value of the first argument raised to the power of the second argument. Parameters: a - the base. b - the exponent. Returns: the value ab. public static long round(double a) public static int round(float a) Returns the closest int to the argument. The result is rounded to an integer by adding 1/2, taking the floor of the result, and casting the result to type int. Parameters: a - a floating-point value to be rounded to an integer. Returns: the value of the argument rounded to the nearest int value. public static double sqrt(double a) Returns the correctly rounded positive square root of a double value. Special cases: If the argument is NaN or less than zero, then the result is NaN. If the argument is positive infinity, then the result is positive infinity. If the argument is positive zero or negative zero, then the result is the same as the argument. Otherwise, the result is the double value closest to the true mathematical square root of the argument value. Parameters: a - a value. Returns: the positive square root of a. If the argument is NaN or less than zero, the result is NaN. Graphics using StdDraw We used methods defined in the StdDraw class for graphics. See http://zoo.cs.yale.edu/classes/cs112/cs112-2014-spring/doc_StdDraw/ for list of methods. Color The Color class is used encapsulate colors in the default sRGB color space. Page 33 Color Predefined Variables (Colors) Color.WHITE Color.LIGHT_GRAY Color.GRAY Color.DARK_GRAY Color.BLACK Color.RED Color.PINK Color.ORANGE Color.YELLOW Color.GREEN Color.MAGENTA Color.CYAN Color.BLUE Color Class Methods public Color(int r, int g, int b) Creates an opaque sRGB color with the specified red, green, and blue values in the range (0 255). The actual color used in rendering depends on finding the best match given the color space available for a given output device. Alpha is defaulted to 255. Parameters: r - the red component g - the green component b - the blue component Page 34