Purpose:
To practice constructor overloading, throwing exceptions, and abstraction/use of function-objects.
Part 1: Constructors, Overloading, Visibility
As we slowly reveal features of Java (and other object-oriented langauges) it's your job (through practice) to identify and use these features to design better (e.g., shorter, safer, faster, more usable/maintainable) programs.
This week we touched on constructor overloading, and visibility modifiers, and equality.Do not just copy and modify the lecture notes...
Remember: makes perfect!
Exercise 1:
Design a class to represent dates. Just so we're on the same page... you need to represent the year, month, and day. Make some examples... for instance, today, yesterday, and yours and your partner's birthdays (or fake ones).
Exercise 2:
Design a method asString that returns this Date in a slash separated form, e.g., "5/24/2011".
Exercise 3:
Typing in that year every time is a big pain... overload your Date constructor (i.e., add a new one) that takes just months and days, providing a default of 2011.
Exercise 4:
Design a method inBetween that takes three integers (say a, b, and c) and determines if b is between a and c (i.e., a < b < c).
Exercise 5:
As we discussed... right now it's possible to create obviously bogus dates... assuming your constructor order is year, month, day, then something like:
new Date(2001, 15, -7)Is obviously nonsense. Use your helper method in your Date constructor to make sure that dates are valid... within reason (i.e., you don't need to make sure that February 28th occured in a leap-year, or even that th 31st is in the right month: 1..12, 1..31, and 1000..30000 are fine).If the given date is bad then throw a new RuntimeException with an informative message String. Otherwise, initialize the the fields as normal.
Note: typically the Java language includes specific exception classes that extend RuntimeException. One that is used often for this kind of situation is IllegalArgumentException.
Exercise 6:
The Tester class contains several 'check' methods for testing exceptions. Use the method checkConstructorException to check your new constructor.
The method takes the expected exception (including the message), the name of the class as a string ("Date"), and the arguments that will cause the exception (in order).
Write a test method with several exception tests... at least one per field (bad yesr, month, day).
Part 1: Function-objects: λ in Disguise (or is it the other way around?)
Following the abstraction recipe, we abstract over not only traditional values, but also functions. In object-oriented languages like Java, everything (that includes functions) is an Object, an instance of a Class.
Because return types are tricky in Java (being a statically typed language and all), for now we will stick with predicates.
Exercise 7:
Design classes to represent lists of Strings. You're free to choose interface or abstract class for the list class. Create some examples while you're at it.
Exercise 8:
Design a method shorterThan10 that returns true if this list of strings contains any strings with length less than 10... don't forget to test.
Exercise 9:
Design a method containsFred that returns true if this list of strings contains the string "fred" as an element. In order to support different capitalizations, use a combination of the String methods equals and toLowerCase... don't forget to test.
Note: The link above is to JavaDoc documentation for standard Java Language/Libraries. If you get used to reading them (and with a little trial and error) you can learn to write more complex programs with less code (leveraging the power of other people's code!).
Now, we abstract!!Exercise 10:
Design an interface IPredString to represent predicates over strings with a single method header:
boolean select(String s);
The idea is that specific predicates ('functions') will implement the IPredString and provide a specific implementation of the method to select what we want (or don't want... depending on the overall scheme of things).Exercise 11:
Abstract your two methods into a single method... I would name it orMap... but you're all adults. The implementation of the interface that we abstracted over becomes a parameter to the method... and takes the place of the different parts of the method bodies.
Exercise 12:
In order to test your method, create classes implementing IPredString that match your other methods (i.e., ShorterThan10 and IsFred).
Exercise 13:
Reimplement the old methods using your new method and your implementation of IPredString.
Fields and Free VariablesRemember when we used lambda (and/or local) to write functions that depended on variables outside the function definition?
Something like this should seem familiar:;; starting-with : [Listof String] String -> [Listof String] ;; Keep all the strings in the list that start with ;; the given string (define (starting-with los str) (filter (lambda (s) (and (>= (string-length s) (string-length str)) (string=? (substring s 0 (string-length str)) str))) los)) (check-expect (starting-with (list "complex" "keyboard" "computer" "screen" "company") "comp") (list "complex" "computer" "company"))
Note that this is is not a contrived example... it really works! The important part is that the outer argument, str, is used within the inner function.In standard object-oriented languages like Java that doesn't fly... all functions/methods are attached to data, so, instead we create a class that contains fields for any necessary information.
Exercise 14:
Design a method filter for your list of string classes that returns a new list of all the strings for which the given IPredString returns true.
Exercise 15:
Design a method shorterThan that returns a new list of all the strings in this list of strings that are shorter than a given integer. Use your filter method. Your implementation of IPredString should contain a field that represents the number to compare the length of the strings to.
Exercise 16:
Design a method containing that returns all the strings in this list of strings that contain a given string (i.e., anLoS.containing("fred")). Use your filter method. Your implementation of IPredString should contain a field that represents the string to compare with.