Arrays and Methods
Outline Methods that return arrays Methods that take arrays (not) returning an array instance variable java.util.Arrays Methods that take arrays adding up the grades finding the grades to drop
Getting All Assignment Grades Client may want a list of grades to put up on a Web site, for example S.o.pln("<h2>Assignment Grades</h2>"); S.o.pln("<table border>"); for (int i = 0; i < Student.NUM_ASGN; ++i) { S.o.pln(" <tr>"); S.o.pf(" <th>A%02d;</th>%n", (i+1)); S.o.pln(" <td>" + stu.asgnGrades[i] + "</td>"); S.o.pln(" </tr>"); } S.o.pln("</table>"); Assignment Grades A01 100 A02 A03 95 A04 80 A05 87 A06 98 A07 A08 96 asgnGrades is private in Student NOTE: HTML mark-up (the <table>/<th>/<td> stuff) will not be on the test!
A Getter for an Array We know how to write a getter just returns instance/class variable return type is same as data type of variable asgnGrades is the variable it is an int[] so… public int[] getAsgnGrades() { // WARNING: DON'T DO THIS! return asgnGrades; wrong! wrong! wrong! } NOTE: Don't return an array instance variable this way! There's a better way on a later slide.
Returning Arrays Methods can return arrays return type is an array type private static int[] dice(int howMany) … private static String[] wordsFrom(String line) … The array to be returned is (often) new int[] result = new int[howMany]; for (int d = 0; d < howMany; ++d) { result[i] = 1 + (int)(6 * Math.random()); } return result; ArrayReturn.java
Calling an Array-Returning Method Result of method is (often) stored in a variable variable must be same type as return type(*) dice returns an int[], wordsFrom returns a String[] int[] myDice; String[] the Words; myDice = dice(6); theWords = wordsFrom("These are the words"); methods create and return the arrays myDice 5 3 2 4 6 theWords “These” “are” “the” “words” (*) Except for things like an int return value saved into a double variable…. NOTE: you cannot save an int[] into a double[] variable!
Exercise Make a method that returns a specified number of copies of a String in an array Call the method to create an array containing three copies of "Hello", and save the result in a local variable named greeting greeting Hello Hello Hello
Variable Names and Arrays Name of array inside method does not need to match the name of the array in the caller because they’re two different variables int[] myDice = dice(6); … private static int[] dice(int howMany) { int[] result = new int[howMany]; return result; // array variable result ceases to exist // it's the array object that's returned } myDice & result & 5 3 2 4 6
… then disCar is painted green Arrays are Objects Like String, Scanner, Student variable points to/refers to the object different variables can refer to the same object such co-reference can cause problems Car variables Car objects & myCar: disCar and myCar are not two different cars. They’re two different names for the same car. & disCar: & stevesCar: if I paint myCar green… … then disCar is painted green
Using the Grades Array getAsgnGrades() returns an array object so when we do… int[] myCopyOfGrades = stu.getAsgnGrades(); …we’re not actually getting a copy of the array… …we’re getting the array itself… & stu: & myCopyOfGrades: name: A_NUMBER: asgnGrades: Dent, Stu A00000001 100 77 80 85 &
Hacking the Grades Array …and if we have the array itself… we can change the values inside it myCopyOfGrades[1] = 800; myCopyOfGrades[2] = -50; Student class is no longer protecting its variables! & stu: & myCopyOfGrades: name: A_NUMBER: asgnGrades: Dent, Stu A00000001 100 77 80 85 & 800 -50
Protecting Array Instance Variables Protect variables by returning a copy myCopyOfGrades = stu.getAsgnGrades(); myCopyOfGrades[1] = 800; myCopyOfGrades[2] = -50; client has no access to the originals & stu: & myCopyOfGrades: name: A_NUMBER: asgnGrades: Dent, Stu A00000001 100 77 80 85 & 100 77 80 85 800 -50
Creating a Copy of an Array What needs to be done: make a new array of the correct size copy all the values of the old array into the new public int[] getAsgnGrades() { int[] copy = new int[asgnGrades.length]; for (int i = 0; i < copy.length; ++i) { copy[i] = asgnGrades[i]; } return copy; 100 77 80 85 & asgnGrades: & copy: 100 77 80 85
An Easier Way to Copy Often need to copy an array Java makes it easier for us don’t need to write all that code someone’s already done it for us! just say what array and how much of it to copy public int[] getAsgnGrades() { // THIS is the way to return an array instance variable return Arrays.copyOf(asgnGrades, NUM_ASGN); } NOTE: This is the better way I promised you earlier.
The Arrays Class Arrays class provides many useful methods copyOf – copies an array copyOfRange – copies part of an array equals – checks if two arrays have same elements fill – fills an array with a given value sort – sorts an array toString – makes a String representing the array Needs to be imported import java.util.Arrays;
A Convenience Printing an array object gets weird output int[] arr = new int[]{10, 2, 130, 40}; System.out.println(arr); Arrays has a method to make it nicer: System.out.println(Arrays.toString(arr)); [I@1db9742 [10, 2, 130, 40]
Arrays.copyOf Returns a new array of the size requested extra elements of the copy are zeroed out int[] longCopy = Arrays.copyOf(asgnGrades, 6); some elements can be left off int[] graded = Arrays.copyOf(asgnGrades, numGraded); 100 85 & asgnGrades: 2 numGraded: 100 85 & graded: 100 85 & longCopy:
Aside To track the number of graded assignments: need a private static variable for that value private static int numAsgnGraded = 0; want a getter and setter for that variable setter should only allow valid assignment numbers (left as exercise) want a public getter for the graded assignments public int[] getGradedAsgns() { return Arrays.copyOf(asgnGrades, numAsgnGraded); } NOTE: It is possible to create an array with zero elements!
Arrays as Arguments to Methods [Brackets] pick out one element of an array asgnGrades[0] picks out 1st element of asgnGrades Don’t use them when sending the whole array! it’s Arrays.copyOf(asgnGrades, NUM_ASGN); not Arrays.copyOf(asgnGrades[], NUM_ASGN); not Arrays.copyOf(asgnGrades[0], NUM_ASGN); .class expected cannot find symbol: class asgnGrades unexpected type: required value found class no suitable method for method copyOf(int, int)
Methods that Take Arrays Can create our own methods that take arrays int asgnSum = sumArray(asgnGrades); just specify correct return/parameter types! asgnGrades is an int[]; asgnSum is an int private static int sumArray(int[] arr) { int sum = 0; for (int i = 0; i < arr.length; ++i) { sum += arr[i]; } return sum; Remember: array names don’t have to match! Sadly, java.util.Arrays does not give us this method.
Command Line Arguments Remember how we declare main? public static void main(String[] args) never really explained String[] args it’s an array of Strings... ...passed into your program... ...from the “command line” prompt] java PrintArgs command line arguments My 3 command line arguments were: 0: "command" 1: "line" 2: "arguments"
Command Line Arguments Add words after the name of the class They get passed to the program (unless they start with < or >, or ...) Appear in the String[] parameter of main each word is a separate array element prompt] java PrintArgs command line My 2 command line arguments were: 0: "command" 1: "line"
NetBeans & the Command Line File > Project Properties… or right-click on project name in Projects pane
Command Line Arguments You can use args like any other array ask it its length loop thru its elements ask for some element System.out.println("My " + args.length + " arguments:"); for (int i = 0; i < args.length; i++) { System.out.println(i + ":\t\"" + args[i] + "\""); } My 2 arguments: 0: "command" 1: "line" args “command” “line”
args is a String[] OK to have a String[] Even if you type in numbers! can have an array of anything (pretty much) Even if you type in numbers! you can use Integer.parseInt(args[i]) to get the integer value of args[i] prompt] java PrintArgs 5 10 My 2 command line arguments were: 0: "5" 1: "10" see AddArgs.java
Arrays as Parameters args is a String[] parameter for main Other methods can have [] parameters, too just declare the parameter to be an array! public static int sumArray(int[] arr) It’s just like any other parameter gets its value from the method call It’s just like any other array it knows how long it is
Why a Method to Sum Arrays? Can use it to add up assignment grades then divide by NUM_ASGN for getAsgnGrade Can use it to add up lab grades then take min with 100 for getLabGrade Can use it to add up test grades then divide by NUM_TEST for getTestGrade It’s something we’ll want to do multiple times with different arrays
Calculating Assignments Grade Currently average of all assignment grades Want to drop two lowest find the lowest grade int lowestGrade = asgnGrades[0]; for (int i = 1; i < NUM_ASGN; ++i) { lowestGrade = Math.min(lowestGrade, asgnGrades[i]); } 100 85 78 77 & asgnGrades: lowestGrade: 77 100
Calculating Assignments Grade Still need second lowest lowest greater than lowestGrade? int secondLow = asgnGrades[0]; for (int i = 1; i < NUM_ASGN; ++i) { if (asgnGrades[i] > lowestGrade) { secondLow = Math.min(secondLow, asgnGrades[i]); } 100 85 78 77 & asgnGrades: lowestGrade: 77 100 secondLow: 78 85 100 Note: this looks right, but it’s wrong!
Calculating Assignments Grade Still need second lowest lowest greater than lowestGrade? int secondLow = asgnGrades[0]; for (int i = 1; i < NUM_ASGN; ++i) { if (asgnGrades[i] > lowestGrade) { secondLow = Math.min(secondLow, asgnGrades[i]); } 100 85 77 & asgnGrades: lowestGrade: 100 77 secondLow: 85 100 See? Wrong!
Find Two Smallest Sort the array, then pick the front two Problem: java.utils.Array has a sort method Problem: sorting the array will break getAsgnGrade(int) grades won’t be in the proper locations any more getAsgnGrade(1) smallest grade on any assignment but that’s wrong! Solution: sort a copy of the grades array
Sorting an Array Just give the array to Arrays.sort It’ll come back sorted int[] a = new int[]{4, 2, 7, 1, 9, 9, 4}; Arrays.sort(a); Works for (almost) any kind of array works for Strings – sort of String[] words = new String[]{"e", "B", "d","c","a"}; Arrays.sort(words); capital letters come first! a 1 2 4 7 9 4 2 7 1 9 words B a c d e e B d c a ArraySorter.java
Sorting a String Array Need to give sort a Comparator an object that says how to sort the Strings String[] words = new String[]{"e", "B", "d","c","a"}; Arrays.sort(words, String.CASE_INSENSITIVE_ORDER); now it sorts into alphabetical order! words e B d c a a B c d e ArraySorter.java
Modifying Arrays Arrays can be modified by methods int[] a = new int[] {1, 2, 3, 4}; doubleEachElement(a); Just a normal method private static void doubleEachElement(int[] arr) { for (int i = 0; i < arr.length; ++i) { arr[i] *= 2; } } a: & 2 4 6 8 1 2 3 4 arr: & ArrayDoubler.java
Doesn’t Work for Primitives Method call passes actual value parameter has same value as argument thus method cannot change argument variable int a = 3; doubleValue(a); … private static void doubleValue(int n) { n *= 2; } a 3 n 3 6 ArrayDoubler.java
Can’t Change Argument Variable Method call passes reference to object parameter points to same object as argument but it’s NOT the same variable! int[] a = new int[] {1, 2, 3, 4}; changeTheArray(a); … public static void changeTheArray(int[] arr) { arr = int[] {5, 6, 7, 8}; } & a 1 2 3 4 5 6 7 8 & arr ArrayDoubler.java
Find Two Smallest To get assignments grade: public int getAsgnGrade() { int[] copy = getAsgnGrades(); // get a copy of asgnGrades Arrays.sort(copy); // sort the copy int sum = sumArray(copy); // add up its elements sum -= copy[0] + copy[1]; // subtract two smallest return (int)((double)sum / (NUM_ASGN - 2) + 0.5); } 100 85 77 & asgnGrades: 100 85 77 & copy: sum: 339 185 77 85 100 93
Not Always Two Smallest Might have eleven assignments and drop three want to make code easy to change to that create a constant and a method public int getAsgnGrade() { // get dropped grades int[] drops = getSmallest(asgnGrades, NUM_DROPS); // calculate return value int sum = sumArray(asgnGrades) - sumArray(drops); return (int)(0.5+(double)sum/(NUM_ASGN-NUM_DROPS)); }
Get N Smallest Same procedure as before… …but return first few elements as an array private static int[] getSmallest(int[] arr, int n) { int[] copy = Arrays.copyOf(arr, arr.length); Arrays.sort(copy); return Arrays.copyOf(copy, n); } 100 85 77 & arr: 100 85 77 & copy: 77 & n 1 77 85 100 Note: sorting the whole array is not the best way to do it; but it will work….
Trouble-Shooting ArrayIndexOutOfBoundsException NullPointerException tried to access a non-existent array element int[] arr = new int[5]; S.o.pln(arr[10]); // ArrayIndexOutOfBoundsExc. NullPointerException tried to talk to an array element that wasn’t created Student[] myClass = new Student[10]; myClass[0].setName("First, Ingrid"); // NullPointerExc. or to an array field that hasn’t been initialized return labGrade[a – 1];
Next Week Tuesday: catch up and review Thursday: midterm test #2 objects and arrays (you’ll still need to know the earlier stuff, of course) labs 6 to 9 assignments 5 to 8 Sample test/questions have been posted sample answers posted later do the sample test before you look at the answers!