Radford University ITEC

ITEC120-ibarland (incl. office hrs)infolectureslabshws

lab11: for-each practice

Today's lab will have you modify a for-each loop, as well as a while-loop using an iterator.
You may work in pairs, or individually.
We will not check off today's lab, but its questions will be fair game for tomorrow's Chapter-6 quiz.

  1. Download the code from class (.jar), saving it to the computer's disk (noticing which directory you're saving it in). Then, start BlueJ and select Project > Open non-BlueJ.... You should see a project with classes WhilePractice and ArrayIterator.
    If you have troubles with this, you can cut-and-paste the lecture code WhilePractice.java as well as ArrayIterator, an extra class needed for part 3 below.
  2. Recall/review the example from lecture, where we used a for-each loop to look at each file inside a directory:
      import java.io.File;
    
      /** 
       *  Return The sum of the length of each file immediately inside directoryName.
       *    Doesn't recur into any sub-directories (but does include any size a directory
       *    itself takes up, aside from its sub-contents).
       * @param  directoryName  The pathname of a directory. 
       * @return The sum of the length of each file immediately inside directoryName.
       */
      public static String directoryListing( String directoryName ) {
        // Convert the directoryName into a File object, so we can get its size etc.:
        final File theDirectory = new File( directoryName );
        // Note that we import'd java.io.File.
    
        if (theDirectory.isDirectory()) {
    
           long fileLengthsSoFar = 0; // Accumulate the sum of all immediate file sizes.
           String listingSoFar = "";
    
    
           for ( File f : theDirectory.listFiles() ) {  // For each `f' in the directory-listing...
             textualListing += f.toString() + "\t\t\t" + f.length() + "\n";
             listingSoFar += f.length();            // Add f's length to our sum.
             }
    
           return listingSoFar + "\nTotal length: " + fileLengthsSoFar + "\n";
    
           }
        else {
          // Hmm, this file wasn't a directory; print a message to System.err.
          String errMsg = "immediateDirectorySize: " + directoryName + " is not the name of a directory.";
          System.err.println( errMsg );
          return errMsg;  // Is this an appropriate sentinel value?  I want to return 'false', but can't!
          }
        }
    
  3. Now, write a similar function int countJavaFiles(String) which takes in a directory-name, and counts how many of the files in that directory end in1 .java.
    Hint: use the String method endsWith.
    You can test your code by running it on various BlueJ project files from previous labs on your H: drive — the file name (on Windows) will be something like "H:\itec120\my-labs\", depending on exactly how you named your files.
  4. Write a method boolean hasJavaFiles(String) which takes in a directory-name, and returns true if (and only if) that directory contains any .java files.
    (Hint: use the previous function, to make your program one line.)
  5. While it is simple code to have #4 call #3, there is also a performance penalty: even if you find a .java right off the bat, your code still looks at every single file in the directory. This is a drawback of the for-each loop.

    Since a for-each loop seems not to be appropriate, instead write boolean hasJavaFiles_v2(String), which uses a while loop and an iterator.
    Hint: your while-loop will keep track a variable “foundSoFar”. You only want to continue your loop as long as there are more files to consider, and you haven't yet found any java file so far.

    Some notes:

Wed.'s solution

ITEC120-ibarland (incl. office hrs)infolectureslabshws


2006.Nov.03 (Fri)

Experimenting with references

We can pass object references as parameters, just like anything else. What actually is being passed to the function is a piece of paper which has a reference written down on it. For example, we saw Kennel.setDog(), which is passed a piece of paper, upon which is a reference to some particular Dog.

  1. Consider the method:
    class Dog {
      // ...fields and other methods omitted...
    
     /** Have this and otherDog exchange their ages.
       * A very useful method for sitcoms and Disney movies.
       * @param otherDog the dog who we'll swap ages with.
       */
      void swapAge(Dog otherDog) {
        // ... WRITE THIS METHOD, in a moment ...
        }
    
      }
    
    1. Draw pictures, showing what happens when we evaluate:
      Dog yourDog = new Dog( "rex",  5);
      Dog myDog   = new Dog( "fido", 7 );
      Dog worldsBestDog = myDog;
      
      myDog.toString()
      (myDog == worldsBestDog)   // Should be ...???
      
      myDog.ageOneYear();        // myDog is still the same dog, just older.
      yourDog.swapAge( myDog );  // myDog is still the same dog, just younger.
      
      myDog.toString()
      (myDog == worldsBestDog)   // Should be ...???
      
    2. Now, go ahead and write Dog.swapAge(Dog).
      (For starting code, save-to-disk lab11-Dog-Kennel.jar, and then from within BlueJ select Project > Open Non BlueJ….)
  2. What does the following code do?
      Dog badClone() {  // Not an evil clone, just broken: no new Dog is made.
        Dog d;
        d = this;    // Note that "new Dog()" is *not* getting created.
        return d;    // A three-line version of "return this".
        }
    
    which we then test by writing
    Dog d1 = new Dog( "lassie", 3);
    Dog d2 = d1.badClone();
    (d1 == d2)       // Should this be true, or should it be false?
    
    Draw pictures of what happens, when you run the tests.
  3. If you want to (successfully) clone2 a Dog, you must call new Dog:
    class Dog {
      /**
       * @return a new dog which looks just like this one,
       *  but is not == to this one..
       */
      public Dog clone() {
        // ... WRITE THIS METHOD ...
        }
    
      }
    
    The method be called via:
    Dog d3 = new Dog( "lassie", 3);
    Dog d4 = d3.Clone();
    (d3 == d4)       // Should this be true, or should it be false?
    
  4. Now that you're comfortable writing methods which return Dogs, try this:
    class Dog {
    
      /**
       * @param partner the dog who is breeding with this.
       * @return a new puppy dog, whose age is 0 and whose name is a blend
       *    of this's and partner's names.
       *    For example:
       *    (new Dog("rex",4)).breed( new Dog("fifi", 6) ) = new Dog( "refi", 0 );
       */
      public Dog breed( Dog partner ) {
        // ... WRITE THIS METHOD ...
        }
    
      }
    
    (You can use a hyphenated compound name, instead of a blended name, if you prefer.)

Fri.'s solution (run testDog)


1If you prefer, you can count files with some other criterion — e.g. those files whose size is more than 1000000 (1MB).      back

2 Btw, note that some people feel there are good reasons to avoid implementing clone, due to the danger of an object and its clone sharing state. For instance, if we clone a Kennel, should that cloned Kennel contain identically the same Dogs as the original? Or, will the cloned Kennel contain clones of those Dogs? It's highly problem-specific, as to what the correct answer should be.      back

ITEC120-ibarland (incl. office hrs)infolectureslabshws


©2006, Ian Barland, Radford University
Last modified 2006.Nov.10 (Fri)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme