Tirgul 5 Feedback from exercises Arrays Nested loops
Tirgul 5 • • • Feedback from exercises Arrays Nested loops & 2 D arrays 1
Common mistakes in ex 3 n n Not defining String/repeating Strings as consts many people wrote a method to get the parameter input from the user, but within it - repeated the input procedure 3 times (copy-paste), instead of creating a single method that prints a message, reads and verifies the input (and call it 3 times with a different message). private int get. Input(String msg, int min. Legal. Value, int max. Legal. Value) 2
Ex 4 3
Arrays – basic use 4
Initializing Arrays At Creation Time int[] numbers={5, 15, 5, 6, 5}; boolean[] bits= {true, false, true}; String[] words = {“hi”, ”bye”); Position[] positions = {new Position(1, 2), new Position()}; 5
Working with the Command Line Congratulations! • We can finally understand the entire signature of the main function. • 6
Command Line Arguments n The main method takes a String[] as a parameter. n n public static void main(String[] args) The contents come from the command line that called the program: n java Hello. Command. Line how are you 0 1 “how” “are” 2 “you” args 7
Example: public class Hello. Command. Line { public static void main(String[] args){ System. out. println("There are " + args. length + “ arguments"); System. out. println("They are: "); for(int i=0; i<args. length; i++){ System. out. println(args[i]); } } } 8
Redirecting the Input and Output of Programs The following saves the output of the program to the file out. txt (instead of printing it): java My. Class arg 1 arg 2 >out. txt To use input from a file (not from keyboard): java My. Class arg 1 arg 2 <input. txt Or we can combine: java My. Class arg 1 arg 2 <input. txt >out. txt These are all very useful features of the shell and work on any command (not just Java). 9
One more helpful shell command n If you are working on CSE computers from outside and would like to transfer a file to yourself maybe the easiest way is to use mutt <email-address> -a <file> < /dev/null For example: mutt mezuman@cs. huji. ac. il –a ex 4. jar < /dev/null 10
Common Array Errors: public class Test { public static void main(String[] args) { String[] words; int num = words. length; //no array there yet! Won’t compile words[0]="hi"; words = new String[15]; crashes the num = words[0]. length(); //no object there yet! program words[15]="Hello"; //out of bounds! } } Exception in thread "main" java. lang. Null. Pointer. Exception at Test. main(Test. java: 7) Exception in thread "main" java. lang. Array. Index. Out. Of. Bounds. Exception: 15 at Test. main(Test. java: 8) 11
Arrays of length 0 n It is legal to create an array of length 0. char[] letters = new char[0]; int num = letters. length; //okay. char letter = letters[0]; //out of bounds! n Notice the difference from these lines of code: char[] letters = null; //Allowed. int num = letters. length; //null pointer exc. char letter = letters[0]; //null pointer exc. 12
clone() n The “method” clone() creates a copy of the array and returns it: int[] nums 1 = new int[5]; // …put numbers into the array… int[] nums 2 = nums 1; int[] nums 3 = nums 1. clone(); nums 1 nums 2 nums 3 1 -2 0 8 8 13
Call by Reference vs. Call by Value – Test Yourselves n n In function calls, technically, arguments are always passed by-value (copied into a local variable in the function) When complex objects are passed, we get the effect of call by-reference (the local variable is an alias of the original one) The actual reference value is passed by value. The function gets direct access to the original object in the memory, and can influence it. 14
Call by Reference vs. Call by Value – Test Yourselves n We want to swap the values of two variabls using a method: public staic void main(Sting[] args){ int a = 5, b = 10; swap. X(a, b); System. out. println(“a=“+a+” b=“+b); l }
Call by Reference vs. Call by Value – Test Yourselves public void swap 0(int a, int b){ int temp = a; a = b; b = temp; } Useless public void swap 1(int[] a, int[] b){ int[] temp =a; a = b; b = temp; Useless } n Which of these is useless? 16
Call by Reference vs. Call by Value – Test Yourselves n We want to swap the values of two variabls using a method: public staic void main(Sting[] args){ int[] a = {5}, b = {10}; swap. X(a, b); System. out. println(“a=“+a+” b=“+b); l }
Call by Reference vs. Call by Value – Test Yourselves public void swap 2(int[] a, int[] b){ int[] temp =a. clone(); a = b. clone(); Useless b = temp; } public void swap 3(int[] a, int[] b){ for(int i=0; i<a. length; i++){ int temp = a[i]; a[i] = b[i]; Useful b[i] = temp; } } n Which of these is useless? 18
Call by Reference vs. Call by Value – Test Yourselves n n Remember that the reference is copied into a local variable in the function (object aliasing). In the useless examples the value of the local reference variables is changed (changing what a, b, temp point to). This doesn’t influence the original object in the memory, or the original reference to it. The useful example changes the values of the object’s properties (the array’s cells). 19
Examples of arrays in action 20
Random Shuffle public static void main(String[] args){ final int NUMBERS = 10; int[] numbers = new int[NUMBERS]; for(int i=0; i<numbers. length; i++){ numbers[i] = i; } shuffle(numbers); Load up the array with numbers. Randomly shuffle the array for(int i=0; i<numbers. length; i++){ System. out. print(numbers[i] + " "); } System. out. println(); Print the results } 21
How do we shuffle? n n n First, we randomly select the element that will appear last in the array, and swap it into place. Then, we’ll select the 2 nd to last element, and swap it into place. Etc. We use java. util. Random – an object that selects random numbers. 22
Random Shuffle Need to import java. util. Random; private static void shuffle(int[] numbers) { Random rand = new Random(System. current. Time. Millis()); for(int i=numbers. length-1; i>=1; i--){ swap(numbers, i, rand. next. Int(i+1)); } } private static void swap(int[] numbers, int i, int j){ int temp = numbers[i]; This will change the array numbers[i] = numbers[j]; in the calling method since we are working through numbers[j] = temp; references! } 23
Nested Loops & 2 D Arrays
Powers Table n We would like to calculate the non-negative powers of the positive integers n n Notice that there’s a difference between positives and non-negatives Positives integers are 1, 2, 3, … Non-negatives are 0, 1, 2, 3, … Calculating the powers of a single integer is easy, as demonstrated in 2 more slides n We are not going to use Math. pow() 25
Powers. Printer Ctor //this class a prints powers table for numbers 1 -highest. Number and powers 0 -highest. Power public class Powers. Printer { //consts private static final int DEFAULT_HIGHEST_NUMBER = 5; private static final int DEFAULT_HIGHEST_POWER = 2; //members private int highest. Number; private int highest. Power; Default highest number, power to which the table is generated Highest number, power to which the table is generated //ctor public Powers. Printer(int highest. Number, int highest. Power) { //sets highest. Number if (highest. Number <= 0) { System. err. println("highest number must be positive. set to default value"); this. highest. Number = DEFAULT_HIGHEST_NUMBER; } else { this. highest. Number = highest. Number; } } //sets highest. Power if (highest. Power < 0) { System. err. println("highest power must be non-negative. set to default value"); this. highest. Power = DEFAULT_HIGHEST_POWER; } 26 else { this. highest. Power = highest. Power; }
Powers. Printer – Table & Rows //prints a full table public void print. Table() { } Prints a full powers table in a topdown design style. The table consists of single rows //prints table rows in a loop for (int i = 1; i <= highest. Number; i++) { print. Row(i); } Prints a single row in a top-down design style. The row consists of single power elements //prints row. Number's powers by calling calc. Power for (int j = 0; j <= highest. Power; j ++) { System. out. print(calc. Power(row. Number, j) + "t"); } //prints a single row public void print. Row(int row. Number) { } System. out. println(""); 27
Powers. Printer – A Single Power Notice that calc. Power() is defined static since it only provides an “external” calculation and does not interact with some specific instance data members private static long calc. Power(int number, int power) { /* Assumptions: 1) number is positive 2) power is non-negative */ //power of 0 long result = 1; Since calc. Power() is a private method, it’s the programmer’s responsibility to provide this method the right arguments Follows the mathematical definition of the power function. //multiply current result by number - power times for (int i = 1; i <= power; i++) { long is another type, very result *= number; similar to int but capable } } return result; of representing larger numbers 28
Powers. Printer – Main public static void main(String[] argv) { argv is a Strings array and has a length member //verify that 2 arguments were given if (argv. length < 2) { System. err. println("n. USAGE: java Powers. Printer <highest-number>" + " <highest-power>n"); System. exit(-1); If the user types The whole program terminates } non-integer arguments, with exit code of -1 on java will throw System. exit(-1) Number. Format. Exception //get user arguments - assuming legal argument types during runtime. int user. Highest. Number = Integer. parse. Int(argv[0]); int user. Highest. Power = Integer. parse. Int(argv[1]); No instance needed yet – //calculates user. Highest. Number ^ user. Highest. Power static method call System. out. println( Powers. Printer. calc. Power(user. Highest. Number, user. Highest. Power)); … 29
Powers. Printer – Main (2) … //create an instance of Powers. Printer pp = new Powers. Printer(user. Highest. Number, user. Highest. Power); //prints a single row int row. Number = 2; System. out. println("n. Single row number " + row. Number); pp. print. Row(row. Number); } //prints the full table System. out. println("n. Full table "); pp. print. Table(); 30
Powers. Printer - Analysis n Invoking “java Powers. Printer 3 4” generates the following output : 81 n Single row number 2 1 2 4 8 16 Full table 1 1 1 2 1 3 1 8 27 1 16 81 1 4 9 How many multiplications costs the 2 nd row (for example) n n 1 2 4 8 takes 0 1 2 3 multiplications (2 = 1 * 2) (4 = 1 * 2) (8 = 1 * 2 * 2) Total number of multiplications needed for a row of 5 elements is : 1+ 2 + 3 + 4 =10 !!! 31
Powers. Printer 2 – A Lighter Version public void print. Row(int row. Number) { //set first number to 1 (0 power) long number = 1; } This is the only method of Powers. Printer 2 different from its corresponding method in Powers. Printer //prints row. Number's powers by multiplying number by row. Number for (int j = 0; j <= highest. Power; j ++) { System. out. print(number + "t"); number *= row. Number; Instead of invoking calc. Power() } implements the power calculation algorithm originally placed in System. out. println(""); calc. Power() Conclusion : Top-down design isn’t always better Now, a row of N elements takes N-1 multiplications 32
Powers. Printer 3 – Nested Loops public void print. Table() { } for (int i = 1; i <= highest. Number; i++) { print. Row(i); } public void print. Table. With. Nested. Loops() { } public void print. Row(int row. Number) { long number = 1; for (int j = 0; j <= highest. Power; j ++) { System. out. print(number + "t"); number *= row. Number; } System. out. println(""); } //prints table rows in a loop long number; for (int i = 1; i <= highest. Number; i++) { //single row number = 1; for (int j = 0; j <= highest. Power; j ++) { System. out. print(number + "t"); number *= i; } System. out. println(""); } We separated number declaration from its assignment since it needs to be declared only once We multiply number by i which is equivalent to print. Row’s row. Number argument 33
Powers. Printer 3 – Another Look public void print. Table. With. Nested. Loops() { //prints table rows in a loop long number; Rows loop. The current row number is current. Row Generally, i is a legal loop variable name. But renaming it as current. Row makes the code more readable for (int current. Row = 1; current. Row <= highest. Number; current. Row++) { //inside a specific row Actually, we could have left number’s number = 1; {declaration + assignment} attached, but it’s really unnecessary (re-declaring it again and again) } } for (int current. Pow = 0; current. Pow <= highest. Power; current. Pow ++) { System. out. print(number + "t"); number *= current. Row; Powers loop. } The current power number is System. out. println(""); current. Pow. This power too refers to the 34 current row current. Row
Nested Loops 2 D Arrays n n What if we know, we’ll need later to check some powers (within bounds), and The most important thing is the easy / quick access to the power results n n n We wouldn’t like to scan the whole table for the right cell Nor would we like to recalculate the results every time We are willing to “pay” in memory n 35 it (cache) pre-calculate once the whole table, and store
Powers. Table Class public class Powers. Table { //original consts private static final int DEFAULT_HIGHEST_NUMBER = 5; private static final int DEFAULT_HIGHEST_POWER = 2; //original members private int highest. Number; private int highest. Power; Same members & constants as in Power. Printer //new const + member private static final long ILLEGAL_INDICES_ELEMENT = -1; private long[ ][ ] table; //ctor public Powers. Table(int highest. Number, int highest. Power) { … } 36
Powers. Table - Constructor //ctor public Powers. Table(int highest. Number, int highest. Power) { //sets highest. Number if (highest. Number <= 0) { System. err. println("Highest number must be positive. set to default value"); this. highest. Number = DEFAULT_HIGHEST_NUMBER; } else { this. highest. Number = highest. Number; } //sets highest. Power if (highest. Power < 0) { System. err. println("Highest power must be non-negative. set to default value"); this. highest. Power = DEFAULT_HIGHEST_POWER; } else { this. highest. Power = highest. Power; } } //allocates and fills the table create. Table(); This is the only new line 37
Powers. Table – create. Table This method is intended for internal use only (it is not part of the API) private void create. Table(){ There’re highest. Number numbers – [1, …, highest. Number]. There’re highest. Power +1 powers – [0, …, highest. Power] //allocates the table = new long[highest. Number][highest. Power + 1]; //fills the rows’ entries in a loop for (int i = 1; i <= highest. Number; i++) { fill. Row(table[i-1], i); } } We would like to fill the i-th row of table (which index is i-1) with the powers of the number i 38
Heap Diagram 0 1 2 3 Powers’ array are allocated one after the other 4 Rows’ array is allocated When an object (e. g. Powers. Table) is constructed, it is kept in the heap 0 0 0 0 0 1 2 3 5 highest. Number 0 0 3 highest. Power 0 1 2 3 0 0 2 3 table The entries of the long arrays are initialized with 0 – the default long value 0 1 39
Powers. Table - fill. Row private void fill. Row(long[] row, int row. Number) { //power of 0 long number = 1; } fill. Row() doesn’t know and doesn’t care that the parameter row is only a single row belongs to a 2 D array //other powers - multiply number by row. Number for (int j = 0; j < row. length; j ++) { row[j] = number; We could have used number *= row. Number; (highest. Power + 1) instead of } row. length, since there’re highest. Power+1 powers in every row – [0, …, highest. Power] 40
What Just Happened Here? table is created in create. Table table[i-1] is sent as fill. Row’s argument create. Table() is about to invoke fille. Row(table[1], 2) row is created as a parameter of table[i-1] according to call by value concept Heap Stack (create. Table) Stack (fill. Row) table = 87 a 9 f 5 d i=2 row = 5 a 76 bfc table[i -1] = 5 a 76 bfc row. length = 4 number = 1 j=0 Power of 0 number = … Loop begins table[i-1] values were updated !!! 0 1 0 2 0 4 0 8 0 1 2 3 41
Powers. Table – Printing A Table public void print. Table. With. Nested. Loops() { //prints table rows in a loop for (int current. Number = 1; current. Number <= highest. Number; current. Number ++) { //single row – loops over the powers for (int current. Power=0; current. Power<=highest. Power; current. Power++) { Simple internal access to table indices System. out. print(table[current. Number -1][current. Power] + "t"); } } } System. out. println(""); 42
Powers. Table - calc. Power public long calc. Power(int number, int power) { //verify that number is in bounds if ((number < 1) || (number > highest. Number)){ System. err. println("number out of bounds"); return ILLEGAL_INDICES_ELEMENT; } } External access to the powers table within //verify that power is in bounds if ((power < 0) || (power > highest. Power)) { System. err. println("power out of bounds"); return ILLEGAL_INDICES_ELEMENT; } Row number-1 contains the powers of number return table[number - 1][power]; 43
Powers. Table - Main public static void main(String[] argv) { //verify that 2 arguments were given if (argv. length < 2) { System. err. println("n. USAGE: java Powers. Table <max-number> <maxpower>n"); System. exit(-1); } Powers. Table (unlike //get user arguments - assuming legal argument types int user. Highest. Number = Integer. parse. Int(argv[0]); Powers. Printer) has no static int user. Highest. Power = Integer. parse. Int(argv[1]); methods and an instance must be constructed //create an instance of Powers. Table pp = new Powers. Table(user. Highest. Number, user. Highest. Power); //prints the full table System. out. println("n. Full table "); pp. print. Table. With. Nested. Loops(); } //prints a single power System. out. println("n. The " + user. Highest. Power + "-th power of “ + user. Highest. Number + " is : " + pp. calc. Power(user. Highest. Number, user. Highest. Power)); 44
Extra Slides 45
Static Cascade You got an API, implemented the public members / methods but then comes the hard part – thinking )-:
Static. Cascade. Bad This simple class has: A single non-static member (1 + getter Some non-static methods (2 Ctor (3 main - static (4 import java. util. Scanner; //This class demonstrates a badly written code with a static cascade problem public class Static. Cascade. Bad { private String name; //instance name private static Scanner sc=new Scanner(System. in) This class has a private member that affects its methods output //ctor public Static. Cascade. Bad(String name) {this. name = name; } //name getter public String get. Name() {return name; } //Does action #1. If instance name is david - should print: "david says: Action 1 done" public void do. Action 1() { System. out. println(name + " says: Action 1 done"); } public void do. Action 2() { …} Main code is top-down designed. public void do. Action 3() { … } Private methods need to be implemented /* Counts from 1 to 10. Creates a new Static. Cascade. Bad named by the user, prints a menu that begins with the instance name and performs on this instance an action chosen by the user. */ public static void main (String[] argv) { count. From 1 To 10(); System. out. println ("What's the Static. Cascade. Bad name? "); Static. Cascade. Bad scb = new Static. Cascade. Bad(sc. next()); do. Action(scb); do. Action needs the instance data and therefore takes it as an 47} argument
Static. Cascade. Bad - count main is static, count. From 1 To 10 is not … The programmer doesn’t know when to use static, so he tries without the static first Code private void count. From 1 To 10() { for (int i = 0; i < 10; i ++) { System. out. println(i + 1); } } Maybe the static will help? Compiler Static. Cascade. Bad. java: 59: non-static method count. From 1 To 10() cannot be referenced from a static context count. From 1 To 10; () private static void count. From 1 To 10() { for (int i = 0; i < 10; i ++) { System. out. println(i + 1); OK!!! } } Obviously that was the right choice, since this method does not interact with any non-static members or other 48 non-static method
Static. Cascade. Bad - do. Action private static void do. Action(Static. Cascade. Bad instance) { } The programmer concluded from the last example that main can only invoke static method so this method is declared static as well //prints menu and get user chosen option int option = print. Menu(instance); Top-down //performs the chosen action design again… switch (option) { case 1: instance. do. Action 1(); break; The right action is invoked case 2: on the instance argument instance. do. Action 2(); break; case 3: instance. do. Action 3(); break; default: System. err. println("Illegal action"); break; } 49
Static. Cascade. Bad - print. Menu The programmer doesn’t know when to use static, and this method is not invoked directly from main so he tries without the static first Code do. Action is static, print. Menu is not … private int print. Menu(Static. Cascade. Bad instance) { System. out. println(instance. get. Name() + " says : choose an option"); Compiler System. out. println("1) bla"); Static. Cascade. Bad. java: 99: System. out. println("2) bla"); System. out. println("3) bla"); non-static method print. Menu(Static. Cascade. Bad) return sc. next. Int(); cannot} be referenced from a static context Maybe the static will help? 50 int option = print. Menu(instance); private static int print. Menu(…) { … } And one method after the other falls into the hands of the evil static (cascade) OK!!!
The Fixed Code Static. Cascade. Fixed import java. util. Scanner*; //This class is the fixed code of Static. Cascade. Bad public class Static. Cascade. Fixed { //similar code to Static. Cascade. Bad … //main public static void main (String[] argv) { count. From 1 To 10(); } } 51 System. out. println ("What's the Static. Cascade. Fixed name? "); Static. Cascade. Fixed scb = new Static. Cascade. Fixed(sc. next()); scb. do. Action(); do. Action() became a non-static method of this class – Object Oriented Programming
do. Action – A Comparison Original Code Fixed Code It’s a non-static method that is invoked on a specific object no argument needed private static void do. Action(Static. Cascade. Bad instance) { private void do. Action() { //prints menu and get user chosen option int option = print. Menu(instance); //prints menu and get user chosen option int option = print. Menu(); //performs the chosen action switch (option) { case 1: instance. do. Action 1(); break; case 2: instance. do. Action 2(); break; case 3: instance. do. Action 3(); break; default: System. err. println("Illegal action"); break; } } //performs the chosen action switch (option) { case 1: These methods are do. Action 1(); invoked on the break; same object thatcase 2: do. Action() was do. Action 2(); invoked on (this). break; case 3: do. Action 3(); break; default: System. err. println("Illegal action"); break; Similar code correction in } } too 52 print. Menu()
Daily Schedule n n n Let’s create a class that represents an appointment schedule We’ll build an object that will hold the appointments for a single day )later we can have several of these objects in order to build an appointment book for the month. ( 53
public class Daily. Schedule { The first hour in the day private int start; The appointments private String[] schedule; private int events; The number of appointments on that day public Daily. Schedule(int start. Hour, int end. Hour){ if(start. Hour > end. Hour){ //bad input. do our best. end. Hour = start. Hour; } schedule = new String[end. Hour-start. Hour]; start = start. Hour; events =0; } We remember the first hour so we can translate future times to indices in the array correctly. 54
public boolean schedule(String event, int hour){ int index = hour-start; if(index>=schedule. length || index<0 || schedule[index]!=null){ Add a new event at a given return false; hour. Returns true if we could schedule the event } schedule[index] = event; events++; return true; } public String event. At(int hour){ int index =hour-start; if(index<0 || index>=schedule. length ){ return null; Get the event at a given hour. } What if there is no event? return(schedule[index]); 55 }
public String clear(int hour){ int index = hour-start; if(index<schedule. length && index>=0 && schedule[index]!=null){ String event = schedule[index]; schedule[index] = null; events--; Clears a given hour return event; } else{ return null; } } Returns the number of scheduled events. Could we public int number. Of. Events(){ do without this field? Why use it? return events; } 56
public int find. Event(String event){ for(int i=0; i<schedule. length; i++) { if(schedule[i]!=null && schedule[i]. equals. Ignore. Case(event)) return i+start; Looks for a certain event. } return NOT_FOUND; } public String to. String(){ String result = "Daily schedule: n"; for(int i=0; i<schedule. length; i++){ if(schedule[i] != null){ result = result + (i+start) + “ : " + schedule[i]; } Returns a string } representation of this object. return result; } 57
Example: class My. Array { public static void main(String[] args) {. . . } /** * Print the 2 D array nicely, surrounded by lines of ### */ public static void print(int[][] ar) {. . . } } 58
Class My. Array public static void main(String[] args) { int[][] b = new int[3][2]; print(b); . . . } 59
Class My. Array 60
Class My. Array 61
Class My. Array public static void main(String[] args) {. . . int[][] a = null; print(a); . . . } 62
Class My. Array 63
Class My. Array public static void main(String[] args) {. . . a = new int[3][]; print(a); . . . } 64
Class My. Array 65
Class My. Array public static void main(String[] args) {. . . int n = a. length; System. out. println("a has " + n + " rows"); . . . } 66
Class My. Array 67
Class My. Array public static void main(String[] args) {. . . a[0] = new int[6]; a[0][2] = 14; a[0][5] = 26; a[1] = new int[0]; print(a); . . . } 68
Class My. Array 69
Class My. Array public static void main(String[] args) {. . . a[2] = new int[3]; print(a); . . . } 70
Class My. Array 71
Class My. Array public static void main(String[] args) {. . . a[2][0] = 3; a[2][1] = 5; a[2][2] = 13; print(a); } 72
Class My. Array 73
Conclusions n n The whole 2 D array doesn’t need to be initialized all together. A 2 D array is an array of arrays. The “subarrays” don’t have to be of the same length. All the elements (cells) of the array have to be of the same type. If arr is of type int[][], then arr[0] is of type int[] and arr[1][3] is of type int. 74
class Calendar n n Remember class Daily. Schedule? Lets use it to create an annual calendar. 75
class Calendar { private Daily. Schedule[][] days; public Calendar(boolean meuberet) { days = new Daily. Schedule[12][]; // 12 months days[0] = new Daily. Schedule[31]; // January days[1] = new Daily. Schedule[meuberet ? 29 : 28]; // February days[2] = new Daily. Schedule[31]; // March. . . } 76
- Slides: 76