Assignment 8

Due Mar 17, on line

Part of the homework for CS:2820, Spring 2021
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

Simple multiple choice questions, 1 point each:

  1. Here is a bit of Java code:
    Thing t = new Thing();
    t.method( ????? );
    

    Here is a skeleton for class Thing:

    class Thing {
        public interface Mystery {
    	String thing( String i );
        }
        public void method( Mystery param ) {
            // body of method omitted
        }
    }
    

    Which text below would work where ????? is given above:
    a) ()-> "Hello world."
    b) (String i, String j)-> i + j
    c) (Int i)-> "Hello " + i + " times"
    d) (i)-> "This: " + i
    e) (String i)-> i + i

    Answers a), b) and c) have formal parameter lists in the lambda expression that do not match the only method in the Mystery interface. They are ruled out trivially.

    If you try the code under current Java implementations, you find that answers d) and e) both compile and run correctly. What's going on here. Answer e) has a formal parameter list that exactly matches the requirements of the Mystery interface. This is an exact fit. for the correct answer.

    Answer e) is not an exact fit, but modern Java compilers have limited support for type inference. The compiler sees that the declaration of class Thing contains only one functional interface, and that interface is compatible with the call. Therefore, the compiler infers that the parameter requires an instance of Thingy and compiles the code as if the lambda expression explicitly declared its parameter to be a String. Had class Thingy included a second functional interface with an int parameter, the compiler would have been unable to draw a conclusion about the parameter type in d), so it would have complained. The skeleton for given for class Thing did not rule out the possibility that Thing included other details such as a second functional interface, so d( is not the best answer.

  2. Again, with reference to the code fragments from Probelm 1, which of the following could be a potentially useful for the body of method omitted comment?
    a) System.out.print( param )
    b) System.out.print( " " + param )
    c) System.out.print( param( " " ) )
    d) System.out.print( param.thing( " " ) )
    e) System.out.print( param->thing( " " ) )

    Lots of the above options are legal if you try to compile and run the code, but the reason is that all Java classes inherit an implicit toString method from class object. The implicit toString gives rather useless output that looks like Classname@0b1f358A. Except in rare cases like debug output, this is not very useful. Answers a) and b) are not very good answers for this reason.

    Answer c) is wrong because param is an object of a class that implements Mystery, it is not a method.

    Answer e) is wrong because the lambda expression has no parameter list and because param is an object of a class that implements Mystery, and that interface expects a string, not a lambda expression.

    That leaves d). If you try it, d) works just fine, it passes a string containing one space to the implementation of thing given, and that method does whatever the lambda expression you gave for problem 1 suggested. This is a solid good answer.

  3. Suppose we write the following:
    MyClass.method( new Thingy { int m(){ return a + 1; } } );
    

    a) Thingy must be an interface.
    b) Method m in Thingy be final.
    c) a must be static.
    d) The constructor called on this line has an implicit parameter.
    e) Thingy must be an inner class of MyClass.

    We can rule out a) because this line of code would also work if Thingy was an abstract class.

    Answer b) is exactly false, because if method m is final in the abstract class, it is illegal to override it in the anonymous inner class given. If Thingy is an interface, it cannot have abstract non-static methods.

    Answer c) is wrong because whether variable a is static or not is totally irrelevant. What matters is, is a visible and is it final or effectively final.

    Answer e) is correct to a point. Thingy could be an inner class of MyClass, but it could also be an outer class, declared at the global level of the program. It could not be an inner class of some other global class because then it would need to be qualified with that class name, for example OtherClass.Thingy.

    That leaves d), something about an implicit parameter to an implicit constructor. This refers back to the notes and lecture material presented in Lecture 19, March 8, and underlined in the March 10 and 12 lectures. Every inner class, whether anonymous or not, whether created by a lambda expression or not, can be rewritten as an explicit outer class that explicitly implements the interface or abstract class. In the event that the body of the inner class or lambda expression accesses variables of an enclosing block, these variables must be passed to a constructor for the explicit outer class where they are cached in final variables of that outer class. Thus, an implicit construct passing effectively final variables. So, d) is correct.

  4. Look at Java's class PriorityQueue (although this question also applies equally to SortedSet and its subclasses). Creating a PriorityQueue involves setting its comparator. Which of the following is a correct definition of a comparitor for use on objects of class Thingy, assuming that such objects have an int field called val:
    a) new Comparator( a.val, b.val )
    b) (Thingy a, Thingy b)-> Integer.compare( a.val, b.val )
    c) (Thingy a, Thingy b)-> Integer.compare( a, b )
    d) (Thingy a, Thingy b)-> a.val > b.val
    e) (Thingy a, Thingy b)-> a.compareTo( b )

    Answer a) is wrong because Comparator is an interface with no constructors.

    Answer c) is wrong because, Integer.compare() meets the requirements of Comparator <;Integer>, a and b cannot be coerced into being Integer objects.

    Answer d) is wrong because the queue wants a compare method that works on two Integer or possibly int argument. This method should return less than zero, zero, or greater than zero integer values, not a boolean. (in C and C++, bool is interchangable with int, so this answer might be correct there.)

    Answer e) is wrong because the queue wants a Thingy is not documented as offering a compareTo method for comparison of Thingy objects.

    That leaves b), and more to the point, this lambda expression offers a method for comparing two Thingy objects using integer comparison of their val fields, fields documented to be of type int.

  5. Why does class Integer (Float and Double also do this) offer two ways to do comparison, compare(a,b) and a.compareTo(b)?
    a) This is just a matter of convenience.
    b) compare(a,b) is faster for int variables.
    c) a.compareTo(b) is faster for int variables.
    d) It must do both because Integer implements Comparable.
    e) One works only for int, the other for Integer.


    Answer a) would be fine for blowing of the question if there was not a good answer. There is one, so it is wrong.

    The interface Comparator only mentions two required methods, compare and equals. The compare method does not include just one argument, so it does not require compareTo for integers, therefore d) is wrong.

    If you try them, answers b) and c) are both syntactically correct, and both of them work regardless of whether the val fields of each Thingy are declared to be Integer or int. Therefore, e) is wrong. That leaves the questions of performance.

    Given that a and b are of type int, compare(a,b) is faster than a.compareTo(b). If you write a.compareTo(b), aut-unoboxing expands this to new Integer(a).compareTo(new Integer(b)).

    Given that a and b are of class Integer, a.compareTo(b) is faster than compare(a,b). If you write compare(a,b), autoboxing expands this to compare(a.intValue(),b.intValue()),

    In both cases, the cost of boxing or unboxing dominates the computation. The actual comparison is quite cheap. I did experiments to demonstrate this on trivial litte programs that do stupid things like iterate over all possible int values to make them take long enough to time.