diff --git a/.gitignore b/.gitignore index 7f8865a..7e1aadf 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # IntelliJ project files -solutions/.idea +.idea +solutions/solutions.iml + +# Generated files +out # Temporary files *~ diff --git a/README.md b/README.md index 0834a57..667bcf2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Programming 2: Ally's Tutorial Questions +# Java Programming: Ally's Tutorial Questions The best way to learn a programming language and the concepts that underlie the language's design is to do *lots* of programming. @@ -43,7 +43,7 @@ To help you decide how you should prioritise working through the questions, I ha * Recap: focuses on recapping basic imperative concepts of Java: loops, recursion, variables, arrays and enumerations. * SimpleObjects: covers basic use of objects (with little or no use of interfaces, inheritance, etc.). * Interfaces: covers concepts relating to Java interfaces. -* Streams: focuses on functional programming features of Java: streams, lambdas and method references. +* Functional: focuses on functional programming features of Java: streams, lambdas and method references. * Inheritance: covers the design and implementation of subclasses. * AbstractClasses: focuses on using abstract superclasses to share common state and methods among subclasses. * Generics: focuses on building generic containers, and on technical aspects of Java generics. @@ -63,8 +63,6 @@ As a result, you will likely find that some of your answers differ from the samp I'm very happy to discuss alternative solutions. Also, please get in touch if there are parts of the solutions that you do not understand, of if you spot errors. -TODO: some additional questions on streams are coming soon! - | Label | Name | Topic tag(s) | Depends on | Solution | |---------------------------|-----------------------------------|-------------------------|-------------|----------| | [98e3](questions/98e3.md) | *... 1 4 2 1 4 2 1 ...* | Recap | | [Solution](solutions/98e3.md) | @@ -85,11 +83,14 @@ TODO: some additional questions on streams are coming soon! | [0378](questions/0378.md) | *Comparing people* | Interfaces | | [Solution](solutions/0378.md) | | [6346](questions/6346.md) | *Depth of arithmetic expressions* | Interfaces | | [Solution](solutions/6346.md) | | [e6fd](questions/e6fd.md) | *Bit sets* | Interfaces | | [Solution](solutions/e6fd.md) | +| [fe94](questions/fe94.md) | *Using Stream.map and Stream.filter* | Functional | | [Solution](solutions/fe94.md) | +| [68e6](questions/68e6.md) | *Using Stream.reduce* | Functional | | [Solution](solutions/68e6.md) | | [0f05](questions/0f05.md) | *Coloured points* | Inheritance | | [Solution](solutions/0f05.md) | | [dd4c](questions/dd4c.md) | *Clocks* | Inheritance | | [Solution](solutions/dd4c.md) | | [8f65](questions/8f65.md) | *Lucky battling fighters with inheritance* | Inheritance | [8d24](questions/8d24.md) | [Solution](solutions/8f65.md) | | [845d](questions/845d.md) | *Books and dictionaries* | Inheritance | | [Solution](solutions/845d.md) | | [e93f](questions/e93f.md) | *Apparent and actual types* | Inheritance | | [Solution](solutions/e93f.md) | +| [d3f5](questions/d3f5.md) | *Streams and downcasting* | Functional, Inheritance, Generics | | [Solution](solutions/d3f5.md) | | [5235](questions/5235.md) | *Equality between points* | ObjectEquality | [0f05](questions/0f05.md) | [Solution](solutions/5235.md) | | [710c](questions/710c.md) | *The consequences of overriding `equals`* | ObjectEquality | [5235](questions/5235.md) | [Solution](solutions/710c.md) | | [aa68](questions/aa68.md) | *Symmetric equality testing* | ObjectEqualilty | [5235](questions/5235.md) | [Solution](solutions/aa68.md) | @@ -103,8 +104,12 @@ TODO: some additional questions on streams are coming soon! | [a6e7](questions/a6e7.md) | *Int set iterators* | AbstractClasses, Interfaces | [8a61](questions/8a61.md) [85bb](questions/85bb.md) | [Solution](solutions/a6e7.md) | | [2ffc](questions/2ffc.md) | *Generic stacks* | Generics | [1486](questions/1486.md) | [Solution](solutions/2ffc.md) | | [b401](questions/b401.md) | *Generic sets* | Generics | [8a61](questions/8a61.md) | [Solution](solutions/b401.md) | +| [336b](questions/336b.md) | *Evolving the Set interface* | Interfaces, Advanced | [b401](questions/b401.md) | [Solution](solutions/336b.md) | +| [17b1](questions/17b1.md) | *Default methods* | Interfaces, Advanced | | [Solution](solutions/17b1.md) | | [96df](questions/96df.md) | *Tree nodes* | Generics | | [Solution](solutions/96df.md) | | [7041](questions/7041.md) | *Cloning tree nodes* | Generics | [96df](questions/96df.md) | [Solution](solutions/7041.md) | +| [888a](questions/888a.md) | *Generic methods with streams* | Generics, Functional | [68e6](questions/68e6.md) | [Solution](solutions/888a.md) | +| [11e2](questions/11e2.md) | *Bounded generic methods with streams* | Generics, Functional | | [Solution](solutions/11e2.md) | | [c822](questions/c822.md) | *Problems cloning tree nodes* | Advanced | [7041](questions/7041.md) | [Solution](solutions/c822.md) | | [735a](questions/735a.md) | *Generic iterators* | Generics | [85bb](questions/85bb.md) [a6e7](questions/a6e7.md) [b401](questions/b401.md) | [Solution](solutions/735a.md) | | [876b](questions/876b.md) | *Generics and subclasses* | Generics, Inheritance | | [Solution](solutions/876b.md) | @@ -112,7 +117,7 @@ TODO: some additional questions on streams are coming soon! | [b4a5](questions/b4a5.md) | *Observing the garbage collector* | MemoryManagement | | [Solution](solutions/b4a5.md) | | [1ae9](questions/1ae9.md) | *Reusing immutable value objects* | MemoryManagement | [0f05](questions/0f05.md) | [Solution](solutions/1ae9.md) | | [290b](questions/290b.md) | *Memory leaks in Java* | MemoryManagement, Advanced | | [Solution](solutions/290b.md) | -| [5566](questions/5566.md) | *Exception-throwing stacks* | Exceptions | [question 1486](1486.md) | [Solution](solutions/5566.md) | +| [5566](questions/5566.md) | *Exception-throwing stacks* | Exceptions | [1486](1486.md) | [Solution](solutions/5566.md) | | [a22c](questions/a22c.md) | *No duplicate email addresses* | Exceptions | [dc38](questions/dc38.md) | [Solution](solutions/a22c.md) | | [e093](questions/e093.md) | *Average of numbers* | Exceptions | | [Solution](solutions/e093.md) | | [7e2a](questions/7e2a.md) | *Stack overflow* | Exceptions | | [Solution](solutions/7e2a.md) | @@ -124,7 +129,8 @@ TODO: some additional questions on streams are coming soon! | [1171](questions/1171.md) | *Cloning graphs* | Advanced | | [Solution](solutions/1171.md) | | [f763](questions/f763.md) | *Simulating garbage collection* | Advanced | | [Solution](solutions/f763.md) | | [9a9b](questions/9a9b.md) | *Transposing tunes* | Advanced | | [Solution](solutions/9a9b.md) | +| [b33f](questions/b33f.md) | *Logging using a functional interface* | Advanced | [888a](questions/888a.md) | [Solution](solutions/b33f.md) | ## More hex strings -When I am gone, if someone wants to add more questions then please consume the remaining [hex strings here](questions/hex_strings.md). +When I am gone, if someone wants to add more questions then please consume the remaining [hex strings here](questions/hex_strings.md). diff --git a/google_checks_edited.xml b/google_checks_edited.xml new file mode 100755 index 0000000..6c46a05 --- /dev/null +++ b/google_checks_edited.xml @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/questions/11e2.md b/questions/11e2.md new file mode 100755 index 0000000..02b7324 --- /dev/null +++ b/questions/11e2.md @@ -0,0 +1,38 @@ +[Back to questions](../README.md) + +## 11e2: *Bounded generic methods with streams* + +In a class, `Example`, write a static method, `getSmallestCollection`. For any element type `E` this method should accept a `List`, `collections`, of any type `C` such that `C` is a subtype of `Collection` (including `Collection` itself). + +The return type of the method should be `Optional`. The method should return `Optional.empty()` if `collections` is an empty list. Otherwise, the method should return an optional containing one of the *smallest* elements of the list, as judged by the `size()` method that is available on any subtype of `Collection`. + +For example, if we have this list of sets available: + + final Set s1 = new HashSet<>(Arrays.asList(1, 2, 3, 4)); + final Set s2 = new HashSet<>(Arrays.asList(1, 2)); + final Set s3 = new HashSet<>(Arrays.asList(1, 2, 3, 4)); + final Set s4 = new HashSet<>(Arrays.asList(3, 4)); + final List> listOfSetsOfIntegers = Arrays.asList(s1, s2, s3, s4); + +then doing: + + final Optional> smallestSet = getSmallestCollection(listOfSetsOfIntegers); + +should yield an optional that contains either `s2` or `s4`, as these are the joint-smallest sets in the list of sets. + +Your implementation of `getSmallestCollection` should be a one-liner that streams the list and performs an identity-free reduction. + +Implement a main method that demonstrates your method in action on a list of sets of integers, and a list of lists of strings. + + +**Hints:** The real challenge here is to work out the right signature for the method `getSmallestCollection`. + +* You might try to first implement: + + static Optional> getSmallestCollection(List>) { ... } + + to get your solution working for the explicit case of a list of collections of integers. + +* Then you could work out how to make the method work on lists of collections of some arbitrary type `E`. + +* Finally, you could work out how to make the method work on a list of any subtype of `Collection` (that's the hardest bit). diff --git a/questions/17b1.md b/questions/17b1.md new file mode 100755 index 0000000..2352ea1 --- /dev/null +++ b/questions/17b1.md @@ -0,0 +1,100 @@ +[Back to questions](../README.md) + +## 17b1: *Default methods* + +This question is a synthetic exercise to help you understand the situations where adding a default method to an interface can cause classes that implement that interface to fail to compile. + +Take a look at the classes and interfaces under `solutions/code/tutorialquestions/question17b1/beforedefault`. + +There are three interfaces, `I`, `J` and `K`. + +Interface `I` specifies two overloads of a `foo` method, as well as a `bar` method: + + public interface I { + + int foo(); + + int foo(int x); + + int bar(int x); + + } + +Interface `J` specifies the same single-argument `foo` and `bar` methods as `I` (but no zero-argument `foo` method): + + public interface J { + + int foo(int x); + + int bar(int y); + + } + +Interface `K` extends both `I` and `J`, and adds an additional specification for a zero-argument method, `baz`: + + public interface K extends I, J { + + void baz(); + + } + +This means that to implement `K`, a class needs to provide methods with all of the following signatures: + + int foo(); // Required by I + int foo(int x); // Required by I and J + int bar(int x); // Required by I and J + void baz(); // Required by K + +Now take a look at classes `A`, `B` and `C`. + +Class `A` implements `I`, providing implementations of all the required methods, plus of two additional methods with the following signatures: + + public int foobar(); + public void foobar(int x); + +Class `B` implements both `I` and `J`, providing just those methods required by these interfaces. + +Class `C` implements `K`, providing implementations of the methods required by `I` and `J` as well as the extra method required by `K`. Additionally, `C` provides two further methods with the following signatures: + + public int foobar() throws IOException; + protected int foobar(int x); + +**Your task:** + +1. Add the following default methods to `I`: + + ``` + default int foobar() { + return bar(foo()); + } + + default int foobar(int x) { + return bar(foo(x)); + } + ``` + + Add the following default method to `J`: + + ``` + default int foobar(int x) { + return bar(foo(x)); + } + ``` + + Add the following default method to `K`: + + ``` + default int foobar(int x) { + return I.super.foobar(x); + } + ``` + +2. You should find that the addition of these methods leads to several compilation problems in the implementing classes `A`, `B` and `C`, due to incompatible method signatures. + + For each such problem, deal with it in one of the following ways: + + * Add a method to the class that is failing to compile in order to resolve the clash. (In this case you can implement the method in any way that respects the method's signature; the details of what the method actually does are not important for this question.) + + * Rename a method in the class that is failing to compile by adding `Original` to the end of its name (so that e.g. `foo` would become `fooOriginal`) + + In each case, write a brief comment explaining why you added or renamed the method. diff --git a/questions/336b.md b/questions/336b.md new file mode 100755 index 0000000..9727e22 --- /dev/null +++ b/questions/336b.md @@ -0,0 +1,53 @@ +[Back to questions](../README.md) + +## 336b: *Evolving the Set interface* + +This question involves adding *default* methods to the `GenericSet` interface that you designed in [question b401](b401.md). + +*Note:* if you had trouble completing [question b401](b401.md), you have two choices: + +* You could attempt this question by starting with the [question b401](b401.md) sample solution; + +* You could add default methods to the `IntSet` interface of [question 8a61](8a61.md), rather than to its generic version. + +Let's suppose that our `GenericSet` interface has become popular, and that we now regret not having included some additional methods when we designed the interface. We'll go through how to use default methods to fill these omissions. + +1. Add a `default` method to the `GenericSet` interface called `addAll`. The `addAll` method have `void` return type, and should take an array, `items`, of type `E` as its single parameter, where `E` is the generic parameter associated with `GenericSet` (use `Integer` or `int` instead of `E` if you are working on `IntSet` rather than `GenericSet`). + + For each element `item` in `items`, the `addAll` method should use the `add` method to add `items` to the set. + +2. In a `Demo` class, write a main method that creates a `MemoryEfficientGenericSet` of integers and a `SpeedEfficientGenericSet` of integers, creates some small arrays of integers, and uses `addAll` to add the arrays of integers to each of the sets. Run your `main` method to check that it behaves appropriately. + + Now change your `main` method so that it creates some *large* arrays of integers, and uses `addAll` to add the large arrays of integers to each of the sets. + + (You could look at `Demo.java` from the sample solution for some example code here; see `solutions/code/tutorialquestions/question336b/Demo.java`.) + + You will probably find that `addAll` takes an excessively long time to add a large array of integers to a `MemoryEfficientGenericSet`. Think about why this is. + +3. The default implementation of `addAll` works for any set, but as demonstrated in step 2 is not efficient for `MemoryEfficientGenericSet`s. Override `addAll` in `MemoryEfficientGenericSet` with an implementation that does *not* invoke the default `addAll` implementation, but instead uses a `HashSet` local variable to keep track of the contents of the set. This hash set should be initialized with the contents of the `MemoryEfficientGenericSet`. Then, for each element of `items` (the parameter to `addAll`), you should first check whether the element is in the hash set. If it is, you should move on to the next element; otherwise you should add it directly to the elements of the `MemoryEfficientGenericSet` (without going through the `add` method), and also add it to the hash set of elements that are known to be in the set. + + You should find that, with this specific implementation of `addAll`, the code in your `main` method behaves in an efficient manner. Think hard to make sure you understand why this is the case. + +4. Add one more default method to `GenericSet`. This method should be called `asUnmodifiableSet`. It should take no parameters, and should return a `GenericSet`. The generic set that is returned should be a version of the original set where any methods that could cause the set to be modified are replaced with methods that throw an `UnsupportedOperationException`. + + There are two ways you could approach this. The simple, but somewhat verbose way, is to make a new class, `UnmodifiableGenericSet` that implements the `GenericSet` interface. This class should have a single field of type `GenericSet` representing the set for which an unmodifiable version is being created; this field could be called `wrapped`. The new class should implement all of the required methods of `GenericSet`. The non-mutating methods should be implemented by delegation to `wrapped`: invoking the corresponding method, with the same parameters (if any) on `wrapped`, and returning the result (if any) returned by said method. The mutating methods should be implemented by simply throwing an `UnsupportedOperationException`. + + Recall from [question 85bb](85bb.md)) that we avoided the need for writing a fully separate iterator class by using an *inner class*. It is not possible for an interface to have an inner class (it can have a *nested class*, but not an inner class; read online about nested classes to understand the difference). + + However, we can use an *anonymous inner class* in the implementation of `asUnmodifiableSet`, by having the body of `asUnmodifiableSet` look like this: + + return new GenericSet() { + @Override + public void add(E item) { + throw new UnsupportedOperationException("Attempt to add to an unmodifiable set."); + } + ... /* Implementations of other methods */ ... + }; + + This returns an instance of a new class that implements the `GenericSet` interface, implementing its methods according to the method implementations given between the `{` and `}` following `new GenericSet`. + + If you follow this approach, your anonymous inner class will need to call methods of the `GenericSet` that it is defined inside. This can be achieved by using the syntax `GenericSet.this`. So, for example, in a method inside the anonymous inner class, `isEmpty()` would call the `isEmpty` method of the anonymous inner class, while `GenericSet.this.isEmpty()` would call the `isEmpty` method of the object implementing the outer `GenericSet` interface. + + Try both implementation approaches -- using an explicit `UnmodifiableGenericSet` class and an anonymous inner class, and see which you prefer. Beyond the amount of code you have to write, can you see any pros and cons of the two approaches? + +5. Adapt your `main` method so that it uses `asUnmodifiableSet` to create unmodifiable versions of some sets, and check that the unmodifiable sets behave just like the sets that they wrap if non-mutator methods are called, and that appropriate exceptions are thrown if mutator methods are called. Notice that, due to the use of a default method, you can work with unmodifiable versions of `MemoryEfficientGenericSet`s and `SpeedEfficientGenericSet`s without having had to modify these classes. diff --git a/questions/67dd.md b/questions/67dd.md index b5abc70..14a1fdd 100755 --- a/questions/67dd.md +++ b/questions/67dd.md @@ -25,4 +25,4 @@ Words: 35 Characters: 149 ``` -Reading from standard input can be performed as in question [2d33](questions/2d33.md). +Reading from standard input can be performed as in question [2d33](2d33.md). diff --git a/questions/68e6.md b/questions/68e6.md new file mode 100755 index 0000000..b19be2a --- /dev/null +++ b/questions/68e6.md @@ -0,0 +1,74 @@ +[Back to questions](../README.md) + +## 68e6: *Using Stream.reduce* + +The purpose of this question is to give you practice writing reductions over streams, both with and without identities. + +1. Create a class, `Example`, that we will use as a placholder for the static methods that you will write. + +2. **List concatenation**: Write a static method with the following signature: + + ``` + static List concatenate(List> lists); + ``` + + The method should stream `lists`, to yield a stream of lists of integers, and then should reduce this to a single list, which should be returned. The single list should be the concatenation of all the list. You should use a reduction *with* an identity here, and if `lists` is empty, the result of `concatenate` should be an empty list. + +3. **Find min with identity**: Write a static method with the following signature: + + ``` + static int findMin(List numbers); + ``` + + The method should stream `numbers` and perform a reduction *with* identity to yield the smallest integer in the list, or the largest possible integer if the list is empty. Your reduction should use a *method reference* as its accumulator. + +4. **Find min without identity**: Write a static method with the following signature: + + ``` + static int findMinOrZero(List numbers); + ``` + + The method should stream `numbers` and perform a reduction *without* an identity to yield the smallest integer in the list, or zero if the list is empty. Your reduction should use a *method reference* as its accumulator. + +5. **Find max with identity**: Write a static method with the following signature: + + ``` + static int findMax(List numbers); + ``` + + The method should stream `numbers` and perform a reduction *with* identity to yield the largest integer in the list, or the smallest possible integer if the list is empty. For the sake of practice, your reduction should use a *lambda* as its accumulator (even though a method reference would be more natural). + +6. **Find max without identity**: Write a static method with the following signature: + + ``` + static int findMaxOrZero(List numbers); + ``` + + The method should stream `numbers` and perform a reduction *without* an identity to yield the largest integer in the list, or zero if the list is empty. For the sake of practice, your reduction should use a *lambda* as its accumulator (even though a method reference would be more natural). + +7. **Find min of maxes**: Write a static method with the following signature: + + ``` + static int findMinOfMaxes(List> listOfLists); + ``` + This method should re-use `findMin` and `findMax` to return the smallest maximum among each list in `listOfLists`. + +8. **Demo code**: Write a `main` method to demonstrate that your implementations of these methods works on some example inputs. For example, you could use these list declarations and invocations of the above methods, work out what the expected results should be and check whether your solution does give these results: + + ``` + final List list1 = Arrays.asList(1, 2, 3, 4, 5, 9); + final List list2 = Arrays.asList(1, 10, 100, 1000, 10000); + final List list3 = Arrays.asList(6, 7, 8); + final List> listOfLists = Arrays.asList(list1, list2, list3); + + final List allIntegers = concatenate(listOfLists); + final int maxList1 = findMax(list1); + final int minList2 = findMin(list2); + final int maxEmpty = findMax(Collections.emptyList()); + final int minEmpty = findMin(Collections.emptyList()); + final int maxOrZeroEmpty = findMinOrZero(Collections.emptyList()); + final int minOrZeroEmpty = findMaxOrZero(Collections.emptyList()); + final int minOfMaxes = findMinOfMaxes(listOfLists); + final int minOfMaxesEmpty = findMinOfMaxes(Collections.emptyList()); + final int minOfMaxesListOfEmptyLists = findMinOfMaxes(Arrays.asList(Collections.emptyList(), Collections.emptyList())); + ``` diff --git a/questions/85bb.md b/questions/85bb.md index cef50a4..7919f11 100644 --- a/questions/85bb.md +++ b/questions/85bb.md @@ -55,7 +55,7 @@ You should now find that `StringStackArray` and `StringStackList` no longer compile. This is because they do not implement the `iterator` method. ### Step 3 -In order to fix this, you need to create two new classes: `StringStackArray``Iterator`, +In order to fix this, you need to create two new classes: `StringStackArrayIterator`, and `StringStackListIterator`. Both classes should implement the `StringStackIterator` interface. Writing these classes is a little tricky, but once you have them, implementing the `iterator` method in `StringStackArray` is straightforward: simply @@ -64,7 +64,7 @@ return a new `StringStackArrayIterator`; implementing `iterator` in So, how should you implement the iterator classes? There are two choices: -1. Create a fresh class for each of `StringStackArrayIterator` and `StringStack``ListIterator`. +1. Create a fresh class for each of `StringStackArrayIterator` and `StringStackListIterator`. Let us consider the `StringStackArrayIterator` case. `StringStackArrayIterator` should have a field of type `String[]`: a reference to the contents of the stack. In addition, this class should have a field of type `int` that refers to the stack element that the iterator is currently pointing to. This should be initialised to the top of the stack. This solution is OK, but it requires the internal details of a `StringStackArray` to be indirectly exposed to the separate `StringStackArrayIterator` class, since a `StringStackArrayIterator` is constructed using the internals of a `StringStackArray`. More importantly, this setup allows clients to construct instances of `StringStackArrayIterator` *independently* of any actual `StringStackArray`. This doesn't really make sense. The extent of this problem can be limited by making the `StringStackArrayIterator` only package visible. diff --git a/questions/888a.md b/questions/888a.md new file mode 100755 index 0000000..d52347a --- /dev/null +++ b/questions/888a.md @@ -0,0 +1,34 @@ +[Back to questions](../README.md) + +## 888a: *Generic methods with streams* + +The purpose of this question is to give you practice writing some static methods that use one or more *generic* parameters, and that also use streams. + +1. **Immutable pair.** Write a generic class, `ImmutablePair`, with two generic parameters, `S` and `T` say, that allows the construction of an (`S`, `T`) pair, and retrieval of its first and second components. Override `toString()` so that a pair is represented as a string of the form `(`*string representation of first element*`, ` *string representation of second element*`)`. + +2. **Placeholder class.** Create a class, `Example`, to serve as a placeholder for the static methods you will write. + +3. **Generic list concatenation** Recall the `concatenate` function from [question 68e6](questions/68e6.md), which had the signature: + + ``` + static List concatenate(List> lists); + ``` + + and returned the concatenation of the lists in `lists`. Observe that there is nothing `Integer`-specific about the notion of concatenating lists. + + Write a version of `concatenate` that is generic with respect to some type `T`, and which takes a list of lists of type `List>`, and returns a `List` that is the concatenation of these lists. + +4. **Zip lists of different lengths** Write a static method, `zip`, that is generic with respect to two parameters, `S` and `T`, and that takes two parameters, a list `first` of type `List` and a list `second` of type `List`. The method should return a list of type `List, Optional>>`. At each index *i* less than the minimum size of `first` and `second`, the result should have a pair of present optionals corresponding to the elements at indices *i* of `first` and `second`. At each index *j* (if any) at least the minimum size of `first` and `second` and less than the maximum size of `first` and `second`, the result should have a pair consisting of one present optional and one empty optional; the present optional should be the value at index *j* of the input list, which must exist. + +The `zip` function is not a good fit for using streams, so feel free to use a loop-based solution. If you are interested in playing more with streams, then consider using the `IntStream.range()` method to get a stream of integers as long as the maximum size of the two lists, and then use `mapToObj` to map each integer to the appropriate pair, by `get`ting list elements when they are needed. + +5. **Flattening pairs of optionals** Write a static method, `flatten`, that is generic with respect to two types, `S` and `T`. The `flatten` method should take three parameters: a list, `maybePairs` of type `List, Optional>>`, an element `defaultS` of type `S`, and an element `defaultT` of type `T`. `flatten` should return a list of type `List>` such that: + + * if an element `s` of type `S` is present as the first component of the pair at index *i* of `maybePairs` present, the first component of the pair at index *i* of the result list is `s`, otherwise it is `defaultS`; + * if an element `t` of type `T` is present as the first component of the pair at index *i* of `maybePairs` present, the first component of the pair at index *i* of the result list is `t`, otherwise it is `defaultT`. + + The idea is that the method *flattens* a list of pairs of optionals into a list of pairs, using the given default values wherever an empty optional appears. + + Try to write this method using streams, rather than loops. + +6. **Writing a main method** Add a `main` method to `Example` that demonstrates your example methods in action on some example data. \ No newline at end of file diff --git a/questions/9a9b.md b/questions/9a9b.md index 9c6ebbd..cbb10b0 100644 --- a/questions/9a9b.md +++ b/questions/9a9b.md @@ -75,7 +75,7 @@ structure that will represent these elements! The trick is to exploit the fact Turning tune elements into strings will involve overriding `toString` in your `Note` and `Rest` classes (and possibly also in enumerations you may have created). A quarter-length -"middle C" note should be represented by the string `C-4(1/4)`. A half-length rest should be represented as +"middle C" note should be represented by the string `C4(1/4)`. A half-length rest should be represented as `Rest(1/2)`. Other notes and rests should be represented similarly. The well-known tune Fr\`{e}re-Jaques starting on "middle C" would be represented as a string thus (with some line breaks added): diff --git a/questions/b33f.md b/questions/b33f.md new file mode 100755 index 0000000..5846720 --- /dev/null +++ b/questions/b33f.md @@ -0,0 +1,118 @@ +[Back to questions](../README.md) + +## b33f: *Logging using a functional interface* + +This question will give you practice with quite a range of Java features! You are going to write two functional interfaces: a *logger* interface, with a method for logging a message at a given severity level, and a *string inspector* interface, with a method that takes a string and optionally returns a (severity level, message) pair related to the string's content. + +You are also going to implement a couple of loggers and string inspectors, using direct implementations and lambdas. The problem will illustrate how we can use interfaces to provide abstract notions of logging and string inspection, and implement an algorithm that can inspect all lines of a file and log the results, and that we can instantiate this algorithm with various different notions of string inspection and various different methods for logging. + +1. **Immutable pair.** [Note: if you tried [question 888a](../questions/888a.md) you may copy in the `ImmutablePair` class implemented as part of that question.] Write a generic class, `ImmutablePair`, with two generic parameters, `S` and `T` say, that allows the construction of an (`S`, `T`) pair, and retrieval of its first and second components. Override `toString()` so that a pair is represented as a string of the form `(`*string representation of first element*`, ` *string representation of second element*`)`. +2. **Log level enum.** Write an enumeration class, `LogLevel`, specifying the following severity levels, in increasing order of severity: + - `VERBOSE` + - `INFO` + - `WARNING` + - `ERROR` + - `FATAL` +3. **Logger functional interface.** Write a functional interface, `Logger`, specifying one method: + `void log(LogLevel logLevel, String message);` Use an annotation to indicate that this is a functional interface. Check that, with your annotation, you get a compiler error if you try to add another method to the interface. +4. **String inspector functional interface.** Write a functional interface, `StringInspector`, specifying a single method, `inspect`, that takes a string and returns, optionally, an `ImmutablePair` comprised of a `LogLevel` and a string. + + The idea is that this method will inspect the input string, returning nothing (i.e. an empty optional) if the string is not noteworthy, and a severity level and message if the string is noteworthy. It is up to implementations of this interface to decide what "noteworthy" means in practice. +5. **File inspector class.** Write a class, `FileInspector`, with a single field of type `Logger`, a constructor that populates this field with a given `Logger` reference, and a single method, `inspectFile`, that takes a file name (string) and a `StringInspector`. + + The method should open the file with the given name, and process it line by line. It should invoke the string inspector for each line, and if the string inspector reports that the line is noteworthy, it should invoke the logger with the severity level and message reported by the string inspector. + + You can declare the `inspectFile` method should be declared as throwing `IOException`, to avoid having to deal with exceptions, but feel free to experiment with using a `try...catch` block, e.g. to ignore exceptions, or log a fatal error if an exception occurs. + +6. **File logger implementation.** Write a class, `FileLogger`, that implements the `Logger` interface. This class should have a `BufferedWriter` field, and should be constructed with a file name: the file name should be used to create a buffered reader from a file reader for the given file, throwing an `IOException` when something goes wrong. + + The `log` method should do nothing if the given severity level is `INFO` or `VERBOSE`. Otherwise it should write a line to the buffered writer of the form "*SEVERITY_LEVEL*`:` *message*", where *SEVERITY_LEVEL* is the string representation of the given severity level and *message* is the message string. + + If an `IOException` occurs during the execution of `log`, it should be ignored. + + The class should also have a `close` method that closes the buffered writer, throwing an `IOException` if something goes wrong. + +7. **Known words string inspector implementation.** Write a class, `KnownWordsStringInspector`, that implements the `StringInspector` interface. As fields, this class should have a set of *error words* and a set of *verbose words*, each of which should be a set of strings, and the class should be constructed with a reference with which to populate each of these fields. + + The `inspect` method should split the input string using " ", turning it into an array of strings, and iterate over these strings. Each string that occurs in the set of *error words* should be added to a list of *observed* error words. Each string that occurs in the set of *verbose words* should be added to a list of *observed* verbose words. If no error or verbose words are observed, the method should return an empty optional. Otherwise, a (severity level, message) pair should be returned (packaged in an optional). The severity level should be `ERROR` if at least one error word was observed, and `VERBOSE` otherwise. The message should indicate which error words and which verbose words were observed. + +8. **Writing a demo, using these classes and using some lambdas.** Write a class, `Demo`, with a main method. + + In the main method, check that exactly three arguments are supplied; these should correspond to an input file and two output files. + + Declare a local variable, `stderrLogger`, of type `Logger`, that implements the functional interface `Logger` via a lambda: + + final Logger stderrLogger = (logLevel, message) -> { ... }; + + The body of this lambda should write `message` to standard error, prefixed by `***IMPORTANT***\n` if the severity level is `WARNING` or higher, and prefixed by `*NOTE*\n` otherwise. + + Similarly, declare a local variable, `lineTooLongInspector`, of type `StringInspector`, that implements the functional interface `StringInspector` via a lambda. The lambda should return an optional containing a pair of the form (`ERROR`, "Line too long: *line*") if the given string is more than 100 characters in length, and should return an empty optional otherwise. + + Create three `FileInspector` objects: + + - A `FileInspector` that takes `stderrLogger` as its logger + - Two `FileInspectors` that each take a `FileLogger` as their logger, using `args[1]` and `args[2]` as the output file names + + Create a `KnownWordsStringInspector` with some error and verbose words of your choice. + + Use the following statements to run your file inspectors on the file with name `args[0]`, using your string inspectors: + + System.err.println("Starting inspection 1:"); + inspector1.inspectFile(args[0], lineTooLongInspector); + System.err.println("\nStarting inspection 2:"); + inspector1.inspectFile(args[0], knownWordsInspector); + System.err.println("\nStarting inspection 3 (see " + args[1] + " for details)."); + inspector2.inspectFile(args[0], lineTooLongInspector); + System.err.println("\nStarting inspection 4 (see " + args[2] + " for details)."); + inspector3.inspectFile(args[0], knownWordsInspector); + + At the end of `main`, be sure to close the two `FileLogger` instances that you created. + +9. **Running your program.** For my "known words" string inspector I used "goto", "finalize" and "static" as the error words, and "continue" and "break" as the verbose words. I populated "input.txt" with the following: + + the quick brown fox jumped over the lazy dog + a b c d e f g h i j k l m n o p q r s t u v w x y z now I know my abc next time won't you sing with me? + Dijkstra said that goto is considered harmful; OS developers disagree + I want to goto a warmer place and stop switch ing between tasks so often, all this switch ing makes it hard to finalize anything, and can't continue like this without at least a short break + But for now I will continue to continue until that break comes + + I then ran this command to execute the program: + + java tutorialquestions.questionb33f.Demo input.txt output1.txt output2.txt + + which gave the following output (the output your program gives may of course be a bit different from this, depending on exactly how you chose to emit strings): + + Starting inspection 1: + *** IMPORTANT *** + Line too long: a b c d e f g h i j k l m n o p q r s t u v w x y z now I know my abc next time won't you sing with me? + *** IMPORTANT *** + Line too long: I want to goto a warmer place and stop switch ing between tasks so often, all this switch ing makes it hard to finalize anything, and can't continue like this without at least a short break + + Starting inspection 2: + *** IMPORTANT *** + Observed the following error words: [goto] + + *** IMPORTANT *** + Observed the following error words: [goto, finalize] + Observed the following words of note: [continue, break] + + * NOTE * + Observed the following words of note: [continue, continue, break] + + + Starting inspection 3 (see output1.txt for details). + + Starting inspection 4 (see output2.txt for details). + + Contents of "output1.txt": + + ERROR: Line too long: a b c d e f g h i j k l m n o p q r s t u v w x y z now I know my abc next time won't you sing with me? + ERROR: Line too long: I want to goto a warmer place and stop switch ing between tasks so often, all this switch ing makes it hard to finalize anything, and can't continue like this without at least a short break + + Contents of "output2.txt": + + ERROR: Observed the following error words: [goto] + + ERROR: Observed the following error words: [goto, finalize] + Observed the following words of note: [continue, break] + \ No newline at end of file diff --git a/questions/b4a5.md b/questions/b4a5.md index 1f5a8fc..6ad29a0 100755 --- a/questions/b4a5.md +++ b/questions/b4a5.md @@ -10,17 +10,12 @@ public void finalize(); which is called when an object is garbage-collected. -A developer can override `finalize` to do some house-keeping or sanity checking when an object is disposed of. For example, `finalize` -could be used to ensure that an object has released resources such as file handles before the object is deallocated. +This method was deprecated in Java 9. (See [this post](https://stackoverflow.com/a/56454348) for some interesting insights into why it was deprecated.) As a result, you should not use `finalize` in your code. -Typically `finalize` is used for defensive programming: to guard against unintentional errors (e.g., forgetting to close a file) -that may have occurred elsewhere in -the program. - -In this question, we will use `finalize` to observe the behaviour of the garbage collector. +Neverthelss, experimenting with `finalize` can provide interesting insights into how garbage collection works, and in this question, we will use `finalize` to observe the behaviour of the garbage collector. **Disclaimer:** This exercise is purely educational, to let you see the garbage collector in action, -and to get more experience writing simple Java programs. You should *never* write a real program that abuses `finalize` in this way! +and to get more experience writing simple Java programs. You should likely never write a real program that uses `finalize`, since it is deprecated, and you should *never* write a real program that abuses `finalize` in this way! Write a class, `A`, with a private `int` field called `id`. `A` should have a single constructor, which should take an integer parameter used to initialise `id`. diff --git a/questions/d3f5.md b/questions/d3f5.md new file mode 100755 index 0000000..d5a3f0f --- /dev/null +++ b/questions/d3f5.md @@ -0,0 +1,27 @@ +[Back to questions](../README.md) + +## d3f5: *Streams and downcasting* + +In an `Example` class, write a method `restrictToPositiveIntegers` with the following signature: + + static Stream restrictToPositiveIntegers(Stream numbers); + +Given a stream of `Number`s, the method should return the substream of this stream comprised of only those numbers of type `Integer` whose integer value is positive. + +The body of `restrictToPositiveIntegers` should be a single statement, and it should *not* convert the input stream to a list or any other collection. + +Write a `main` method showing that if you create a `List` called `numbers` populated with various `Integer`, `Float`, `Double` and `Short` values, and then do: + + System.out.println("Positive integers from " + numbers + " are: " + + restrictToPositiveIntegers(numbers.stream()).collect(Collectors.toList())); + +you see precisely the positive integers from your list of numbers being output. + +Try creating a `List` or `List` and invoking `restrictToPositiveIntegers` on a stream derived from each of these lists. You should find that this does not compile. + +**Advanced:** Write a method, `restrictToPositiveIntegersBoundedWildcard`, that can take a stream of any type `T` that is `Number` or one of `Number`'s subclasses and return the substream containing only those positive integers from the original stream. + +**Hints** + +* You will need to use instance testing and downcasting in the implementation of `restrictToPositiveIntegers`. +* For `restrictToPositiveIntegersBoundedWildcard`, the clue is in the name! \ No newline at end of file diff --git a/questions/dd4c.md b/questions/dd4c.md index 1eec6cc..cbda215 100644 --- a/questions/dd4c.md +++ b/questions/dd4c.md @@ -35,6 +35,7 @@ Clock 1 shows: 6 seconds since midnight. Clock 2 shows: 23:59:59 Clock 1 shows: 7 seconds since midnight. Clock 2 shows: 00:00:00 Clock 1 shows: 8 seconds since midnight. Clock 2 shows: 00:00:01 Clock 1 shows: 9 seconds since midnight. Clock 2 shows: 00:00:02 +... ``` Now design a class, `AlarmClock`, which extends `Clock` by storing a specific time diff --git a/questions/f79b.md b/questions/f79b.md index 46ff75d..86a64dd 100755 --- a/questions/f79b.md +++ b/questions/f79b.md @@ -5,7 +5,7 @@ A number *x* is a *perfect palindromic cube* if it is a perfect cube (i.e., *x*=*y*3 for some integer *y*), and it is a palindrome when written in decimal (i.e., it appears the same backwards). For example, 1030301 is a perfect palindromic cube: it is clearly a palindrome, and 1013 = 1030301. -Write a program that enumerates the first 2000 non-negative integers, and indicates which integers yield palindromic numbers when they are cubed. The output of your program should begin: +Write a program that enumerates the first 1500 non-negative integers, and indicates which integers yield palindromic numbers when they are cubed. The output of your program should begin: ``` 0 cubed is 0 @@ -14,6 +14,8 @@ Write a program that enumerates the first 2000 non-negative integers, and indica 7 cubed is 343 ``` +Think about whether or not your program would work properly if you continued significantly larger non-negative integers. If it would not, why not? + **Hints:** You may find the `length` and `charAt` methods of the `String` class useful. These are *instance methods*: you invoke them on a `String` object. Also, you may find the `String.valueOf` method helpful to turn an `int` into a `String`. This is diff --git a/questions/fe94.md b/questions/fe94.md new file mode 100755 index 0000000..afeb490 --- /dev/null +++ b/questions/fe94.md @@ -0,0 +1,30 @@ +[Back to questions](../README.md) + +## fe94: *Using Stream.map and Stream.filter* + +This question is about writing static methods that use the `map` and `filter` operations on streams. + +1. Create a class, `Example`, that we will use as a placeholder for the static methods that you will write. + +2. Write a static method with the following signature: + + static List reverseEachString(List input); + + This method should return a list whose contents are identical to the strings in `input`, except that each string should be reversed. For example, if you invoked `reverseEachString` on the list `[ "hello", "world" ]`, you should get back the list `[ "olleh", "dlrow" ]`. + + Your implementation should comprise a *single* statement that should get a stream from the list, apply multiple map operations to the stream, and collect the result back into a list. + + In particular, you should map the constructor of `StringBuilder` over the stream, to get a stream of `StringBuilder`s, then map the `reverse` method of `StringBuilder` over this stream, then map the `toString` method of `StringBuilder` over the resulting stream to get a stream of `String`s again. + + 3. Now write an alternative version of `reverseEachString`, called `reverseEachStringMonolithic`. This should behave in a functionally identical manner to `reverseEachString`, but instead of applying multiple map operations, a *single* map operation should be used that combines the effects of all of the map operations you used in `reverseEachString`. + +4. Write a static method with the following signature: + + static List sqrtsOfFirstDigits(List input); + + This method should turns `input` into a stream, filter to just those strings that start with a digit, map each remaining string to the integer corresponding to its first digit, and then map each such integer to its square root via the `Math.sqrt` function, returning the resulting stream collected as a list. + +5. Now write an alternative version of `sqrtsOfFirstDigits`, called `sqrtsOfFirstDigitsMonolithic`. This should have the same behaviour as `sqrtsOfFirstDigits`, but should use just one call to `map` and one call to `filter` (as well as the usual calls to `stream` and `collect`). + +6. Write a `main` method to demonstrate that your static methods work on some example inputs. + diff --git a/questions/hex_strings.md b/questions/hex_strings.md index d273fd8..168c4e7 100755 --- a/questions/hex_strings.md +++ b/questions/hex_strings.md @@ -2,17 +2,9 @@ There were originally 500 hex strings. Inflicting more than 500 questions on the first year students would not be nice! -336b -17b1 -11e2 -b33f -fe94 d046 -68e6 c42e 0785 -d3f5 -888a 3499 e900 359f diff --git a/solutions/014e.md b/solutions/014e.md index b5e8740..69ad897 100644 --- a/solutions/014e.md +++ b/solutions/014e.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [014e](../questions/014e): *Random numbers* +## Solution to [014e](../questions/014e.md): *Random numbers* See code at `solutions/code/tutorialquestions/question014e` diff --git a/solutions/0378.md b/solutions/0378.md index b0cfc62..aded901 100644 --- a/solutions/0378.md +++ b/solutions/0378.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [0378](../questions/0378): *Comparing people* +## Solution to [0378](../questions/0378.md): *Comparing people* See code at `solutions/code/tutorialquestions/question0378` diff --git a/solutions/0c21.md b/solutions/0c21.md index 45efc97..41a7e87 100644 --- a/solutions/0c21.md +++ b/solutions/0c21.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [0c21](../questions/0c21): *Properties* +## Solution to [0c21](../questions/0c21.md): *Properties* See code at `solutions/code/tutorialquestions/question0c21` @@ -32,6 +32,10 @@ classes are available in the `instanceofsolution` package (the name of this pack class that extends `House`. Then have `DetachedHouse` extend `House` and implement `Detached`, and have `DetachedBungalow` extend `Bungalow` and implement `Detached` (the setup for the semi-detached and terraced property types is analogous). You might benefit from drawing a class diagram for this arrangement. +However, a problem with this solution is that while a `DetachedBungalow` is an instance of `Bungalow`, `House` and `Detached`, it is not an instance of `DetachedHouse`. +This may be undesirable if we would like to have an is-a relationship between `DetachedBungalow`s and `DetachedHouse`s. +A similar problem affects semi-detached and terraced bungalows, +and for this reason if you implement the second solution you will find that you don't get quite the number of terraced houses when you implement your `main` method. ![Solution class diagram](../diagrams/0c21_solution.png "Inheritance hierarchy for Properties that would be realisable in Java. Note that an interface has been used to simulate multiple inheritance.") diff --git a/solutions/0f05.md b/solutions/0f05.md index d223618..a32a7f9 100644 --- a/solutions/0f05.md +++ b/solutions/0f05.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [0f05](../questions/0f05): *Coloured points* +## Solution to [0f05](../questions/0f05.md): *Coloured points* See code at `solutions/code/tutorialquestions/question0f05` diff --git a/solutions/1171.md b/solutions/1171.md index 91e8617..24702cc 100755 --- a/solutions/1171.md +++ b/solutions/1171.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [1171](../questions/1171): *Cloning graphs* +## Solution to [1171](../questions/1171.md): *Cloning graphs* See code at `solutions/code/tutorialquestions/question1171` diff --git a/solutions/11e2.md b/solutions/11e2.md new file mode 100755 index 0000000..e21fc17 --- /dev/null +++ b/solutions/11e2.md @@ -0,0 +1,21 @@ +[Back to questions](../README.md) + +## Solution to [b33f](../questions/11e2.md): *Bounded generic methods with streams* + +See code at `solutions/code/tutorialquestions/question11e2` + +Compare the sample source code for this question with your solution. + +The signature of the method is: + + public static > Optional getSmallestCollection(List collections); + +Unpicking this a bit, the `E` is the element type of the collections in the list of collections. A simpler method signature is: + + public static Optional> getSmallestCollection(List> collections); + +but this only works if we pass in a `List>`; we cannot pass in a `List>` for example. + +The purpose of `C extends Collection` is to say that "`C` is any type that is a subtype of `Collection`, or `Collection` itself". The true method signature is the same as the simplified method signature, except that `C extends Collection` is introduced right after `E` is introduced, and then `C` is used instead of `Collection` thereafter. + +The solution has a couple of comments starting: "Think about why ..." -- take a look at these and have a think! diff --git a/solutions/1486.md b/solutions/1486.md index f537bc2..a4e0f62 100644 --- a/solutions/1486.md +++ b/solutions/1486.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [1486](../questions/1486): *String stack* +## Solution to [1486](../questions/1486.md): *String stack* See code at `solutions/code/tutorialquestions/question1486` diff --git a/solutions/153d.md b/solutions/153d.md index 8a037a7..f30ab8c 100644 --- a/solutions/153d.md +++ b/solutions/153d.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [153d](../questions/153d): *Exceptions and inheritance (iii)* +## Solution to [153d](../questions/153d.md): *Exceptions and inheritance (iii)* See code at `solutions/code/tutorialquestions/question153d` diff --git a/solutions/17b1.md b/solutions/17b1.md new file mode 100755 index 0000000..7e7863f --- /dev/null +++ b/solutions/17b1.md @@ -0,0 +1,77 @@ +[Back to questions](../README.md) + +## Solution to [17b1](../questions/17b1.md): *Default methods* + +A possible solution is provided via the classes and interfaces under `solutions/code/tutorialquestions/question17b1/afterdefault`. + +* **Class `A`**: This class implements `I`, so possible problems come from the addition of these default methods to `I`: + + ``` + default int foobar() { + return bar(foo()); + } + + default int foobar(int x) { + return bar(foo(x)); + } + ``` + + The zero-argument version of `foobar` is not a problem, since `A` already contains a method with exactly this signature. This overrides the default implementation, and the compiler is happy. + + However, `A` already contained a method with the following signature: + + ```public void foobar(int x);``` + + This is a problem because it has the same argument type as the one-argument default method that has been added to `I`, but a different return type. Overloading on return types is not allowed in Java, so the compiler is not happy. In the sample solution this is dealt with by renaming `foobar` to `foobarOriginal` in `A` (as required by the question). + +* **Class `B`**: This class implements both `I` and `J`, so possible problems come from the fact that the following default methods have been added to `I`: + + ``` + default int foobar() { + return bar(foo()); + } + + default int foobar(int x) { + return bar(foo(x)); + } + ``` + + and the following to `J`: + + ``` + default int foobar(int x) { + return bar(foo(x)); + } + ``` + + The problem is that `B` does not provide a method with signature: + + ```public int foobar(int x);``` + + and both `I` and `J` provide a default method with this signature (remember that interface methods are implicitly public). It is ambiguous which of these methods `B` should inherit, so the compiler is unhappy. + + The solution is to add an implementation of `foobar` with this signature to `B`. As explained in the question, any implementation that respects the method signature is fine; in the sample solution I have provided a `foobar` that uses `return I.super.foobar(x);` to choose the default implementation of `foobar` coming from `I`. + +* **Class `C`**: This class implements `K`, which extends `I` and `J`. Problems could therefore come from the default methods added by `I` and `J` (described above), and the following default method added by `K`: + + ``` + default int foobar(int x) { + return I.super.foobar(x); + } + ``` + + The problem we had with class `B`, where it was unclear which `int foobar(int x)` method should be chosen given the default provided by `I` and `J`, is not a problem here since `K` provides the above default method of this signature, which resolves the ambiguity (by choosing `I`'s `foobar`). + + However, there are two problematic methods in `C`, with these signatures: + + ``` + public int foobar() throws IOException; + protected int foobar(int x); + ``` + + The zero-argument `foobar` is problematic because it declares that it can throw an `IOException`, while the default zero-argument `foobar` specified by `I` does not claim to throw any exceptions. This is illegal: an implementing class cannot implement an interface method in a manner that throws *more* exceptions than the original. This would be bad because client code written against the interface would not be prepared for these additional exceptions. (Throwing fewer exceptions, in contrast, is fine.) + + The one-argument `foobar` is problematic because it has more restricted visibility than the one-argument `foobar` specified in each of `I`, `J` and `K`. An implementing class is not allowed to *decrease* the visibility of an interface method that it implements, and here we have an attempt to decrease visibility from public (recall that interface methods are always public) to protected. + + As required by the question, the solution is to rename each of these troublesome `foobar` methods to `foobarOriginal`. + \ No newline at end of file diff --git a/solutions/1ae9.md b/solutions/1ae9.md index 82158f5..1a70947 100644 --- a/solutions/1ae9.md +++ b/solutions/1ae9.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [1ae9](../questions/1ae9): *Reusing immutable value objects* +## Solution to [1ae9](../questions/1ae9.md): *Reusing immutable value objects* See code at `solutions/code/tutorialquestions/question1ae9` diff --git a/solutions/1aeb.md b/solutions/1aeb.md index 5f9d2ad..9310410 100644 --- a/solutions/1aeb.md +++ b/solutions/1aeb.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [1aeb](../questions/1aeb): *Generic number manipulation* +## Solution to [1aeb](../questions/1aeb.md): *Generic number manipulation* See code at `solutions/code/tutorialquestions/question1aeb` diff --git a/solutions/236b.md b/solutions/236b.md index 08596c7..13fd64d 100644 --- a/solutions/236b.md +++ b/solutions/236b.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [236b](../questions/236b): *Fields for properties* +## Solution to [236b](../questions/236b.md): *Fields for properties* See code at `solutions/code/tutorialquestions/question236b` diff --git a/solutions/2862.md b/solutions/2862.md index df2b99d..1774f31 100644 --- a/solutions/2862.md +++ b/solutions/2862.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [2862](../questions/2862): *Exceptions and inheritance (ii)* +## Solution to [2862](../questions/2862.md): *Exceptions and inheritance (ii)* See code at `solutions/code/tutorialquestions/question2862` diff --git a/solutions/290b.md b/solutions/290b.md index cd57755..e2d965c 100644 --- a/solutions/290b.md +++ b/solutions/290b.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [290b](../questions/290b): *Memory leaks in Java* +## Solution to [290b](../questions/290b.md): *Memory leaks in Java* See code at `solutions/code/tutorialquestions/question290b` diff --git a/solutions/2d33.md b/solutions/2d33.md index f4ec1ed..fecef5e 100644 --- a/solutions/2d33.md +++ b/solutions/2d33.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [2d33](../questions/2d33): *Reversed order of input* +## Solution to [2d33](../questions/2d33.md): *Reversed order of input* See code at `solutions/code/tutorialquestions/question2d33` diff --git a/solutions/2ffc.md b/solutions/2ffc.md index 9f8ca62..a4551d3 100644 --- a/solutions/2ffc.md +++ b/solutions/2ffc.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [2ffc](../questions/2ffc): *Generic stacks* +## Solution to [2ffc](../questions/2ffc.md): *Generic stacks* See code at `solutions/code/tutorialquestions/question2ffc` diff --git a/solutions/30cd.md b/solutions/30cd.md index 7bbbd3c..b1cd717 100644 --- a/solutions/30cd.md +++ b/solutions/30cd.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [30cd](../questions/30cd): *Heap exhaustion* +## Solution to [30cd](../questions/30cd.md): *Heap exhaustion* See code at `solutions/code/tutorialquestions/question30cd` diff --git a/solutions/336b.md b/solutions/336b.md new file mode 100755 index 0000000..b02479b --- /dev/null +++ b/solutions/336b.md @@ -0,0 +1,27 @@ +[Back to questions](../README.md) + +## Solution to [336b](../questions/336b.md): *Evolving the Set interface* + +See code at `solutions/code/tutorialquestions/question336b` + +Compare your solution with the sample solution. + +The default `addAll` method is straightforward: + + default void addAll(E[] items) { + for (E item : items) { + add(item); + } + } + +From a performance point of view, its potential downfall is that it invokes `add` as many times as there are elements in `items`. To see the problem, suppose that `items` has size *N* and the set to which these items is being added to is initially empty. For the first few additions, the call to `add` in `addAll` will iterate over an empty or close-to-empty set. But as the number of elements in the set (thanks to having added many elements from `items`) approaches *N*, each call to `add` for the final elements of `items` will require iterating through close to *N* existing elements, giving *O(N2)* time complexity. + +This explains why, for `MemoryEfficientGenericSet`, the code in your `main` method should have performed so poorly before you implemented a specialised version of `addAll` for this kind of set, because `MemoryEfficientGenericSet` stores set elements in a list, and adding a set element involves iterating over this entire list to see whether the element is already present. + +The more targeted implementation of `addAll` for `MemoryEfficientGenericSet` overcomes this problem by temporarily using a `HashSet`, for which adding and lookup of elements is very efficient, to decide which elements are not already in the set. Using this hash set slightly goes against the memory-efficient intentions of the `MemoryEfficientGenericSet` class, but not too much since the hash set is only alive for the duration of the `addAll` method: it is not the case that every `MemoryEfficientGenericSet` needs to have an accompanying hash set alive at all times. + +For the `asUnmodifiableSet` method, the sample solution shows the use of an anonymous inner class. + +A potential pro of using an anonymous inner class (beyond how much code you need to write), is that this class is *not* available to any other classes in your program. If you write a separate class, `UnmodifiableGenericSet`, you can give this class package visibility so that it is visible only to the package that contains the `GenericSet` interface, but you cannot stop other classes in this package from being able to create their own `UnmodifiableGenericSet` instances. The anonymous class approach makes it impossible for other code to create instances of the class, because the class has no name that could be used in conjunction with `new`. + +This is also a potential con of the approach: there could be a case where you would *like* the class that implement an unmodifiable version of the `GenericSet` interface to be more broadly available, in which case it would need to be in a separate class. \ No newline at end of file diff --git a/solutions/4c70.md b/solutions/4c70.md index 2c22ae2..0c8d409 100644 --- a/solutions/4c70.md +++ b/solutions/4c70.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [4c70](../questions/4c70): *Lottery numbers* +## Solution to [4c70](../questions/4c70.md): *Lottery numbers* See code at `solutions/code/tutorialquestions/question4c70` diff --git a/solutions/5235.md b/solutions/5235.md index ea10ca5..5ac4824 100644 --- a/solutions/5235.md +++ b/solutions/5235.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [5235](../questions/5235): *Equality between points* +## Solution to [5235](../questions/5235.md): *Equality between points* See code at `solutions/code/tutorialquestions/question5235` diff --git a/solutions/5566.md b/solutions/5566.md index 217b3c6..09c03af 100644 --- a/solutions/5566.md +++ b/solutions/5566.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [5566](../questions/5566): *Exception-throwing stacks* +## Solution to [5566](../questions/5566.md): *Exception-throwing stacks* See code at `solutions/code/tutorialquestions/question5566` diff --git a/solutions/5981.md b/solutions/5981.md index fffff82..0a76302 100644 --- a/solutions/5981.md +++ b/solutions/5981.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [5981](../questions/5981): *Shapes* +## Solution to [5981](../questions/5981.md): *Shapes* See code at `solutions/code/tutorialquestions/question5981` diff --git a/solutions/5d30.md b/solutions/5d30.md index a51d494..f4c6afb 100644 --- a/solutions/5d30.md +++ b/solutions/5d30.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [5d30](../questions/5d30): *Unreliable buffered reader* +## Solution to [5d30](../questions/5d30.md): *Unreliable buffered reader* See code at `solutions/code/tutorialquestions/question5d30` diff --git a/solutions/6346.md b/solutions/6346.md index 932a137..354afab 100644 --- a/solutions/6346.md +++ b/solutions/6346.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [6346](../questions/6346): *Depth of arithmetic expressions* +## Solution to [6346](../questions/6346.md): *Depth of arithmetic expressions* See code at `solutions/code/tutorialquestions/question6346` diff --git a/solutions/67dd.md b/solutions/67dd.md index 07be0bc..d04c025 100644 --- a/solutions/67dd.md +++ b/solutions/67dd.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [67dd](../questions/67dd): *Word count* +## Solution to [67dd](../questions/67dd.md): *Word count* See code at `solutions/code/tutorialquestions/question67dd` diff --git a/solutions/68e6.md b/solutions/68e6.md new file mode 100755 index 0000000..f1bbc0b --- /dev/null +++ b/solutions/68e6.md @@ -0,0 +1,11 @@ +[Back to questions](../README.md) + +## Solution to [68e6](../questions/68e6.md): *Using Stream.reduce* + +See code at `solutions/code/tutorialquestions/question68e6` + +Compare your solution to the sample code. + +Note the use in the sample code of `Integer.MAX_VALUE` and `Integer.MIN_VALUE` to get the largest and smallest representable integer values, respectively. + +That `findMinOfMaxes` works by mapping `findMax` over a streamed version of `listOfLists`. It is necessary to collect the result of this map operation back to a list in order to invoke `findMin` on the result. diff --git a/solutions/7041.md b/solutions/7041.md index 41f5ca2..8361621 100644 --- a/solutions/7041.md +++ b/solutions/7041.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [7041](../questions/7041): *Cloning tree nodes* +## Solution to [7041](../questions/7041.md): *Cloning tree nodes* See code at `solutions/code/tutorialquestions/question7041` diff --git a/solutions/710c.md b/solutions/710c.md index 395b3bb..0ddb637 100644 --- a/solutions/710c.md +++ b/solutions/710c.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [710c](../questions/710c): *The consequences of overriding `equals`* +## Solution to [710c](../questions/710c.md): *The consequences of overriding `equals`* See code at `solutions/code/tutorialquestions/question710c` diff --git a/solutions/7206.md b/solutions/7206.md index 0a620df..2c286c4 100644 --- a/solutions/7206.md +++ b/solutions/7206.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [7206](../questions/7206): *Understanding references* +## Solution to [7206](../questions/7206.md): *Understanding references* See code at `solutions/code/tutorialquestions/question7206` diff --git a/solutions/735a.md b/solutions/735a.md index 681ccf8..f8ecdc1 100644 --- a/solutions/735a.md +++ b/solutions/735a.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [735a](../questions/735a): *Generic iterators* +## Solution to [735a](../questions/735a.md): *Generic iterators* See code at `solutions/code/tutorialquestions/question735a` diff --git a/solutions/74d2.md b/solutions/74d2.md index 0f41bab..e7b74f2 100644 --- a/solutions/74d2.md +++ b/solutions/74d2.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [74d2](../questions/74d2): *Exceptions and inheritance (i)* +## Solution to [74d2](../questions/74d2.md): *Exceptions and inheritance (i)* See code at `solutions/code/tutorialquestions/question74d2` diff --git a/solutions/7e2a.md b/solutions/7e2a.md index 7914b0b..3998018 100644 --- a/solutions/7e2a.md +++ b/solutions/7e2a.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [7e2a](../questions/7e2a): *Stack overflow* +## Solution to [7e2a](../questions/7e2a.md): *Stack overflow* See code at `solutions/code/tutorialquestions/question7e2a` diff --git a/solutions/7ec8.md b/solutions/7ec8.md index 44483bf..dadd02a 100644 --- a/solutions/7ec8.md +++ b/solutions/7ec8.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [7ec8](../questions/7ec8): *Battling fighters* +## Solution to [7ec8](../questions/7ec8.md): *Battling fighters* See code at `solutions/code/tutorialquestions/question7ec8` diff --git a/solutions/845d.md b/solutions/845d.md index f343284..1e89fc3 100644 --- a/solutions/845d.md +++ b/solutions/845d.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [845d](../questions/845d): *Books and dictionaries* +## Solution to [845d](../questions/845d.md): *Books and dictionaries* See code at `solutions/code/tutorialquestions/question845d` diff --git a/solutions/85bb.md b/solutions/85bb.md index 9dcd1cd..8e0c002 100644 --- a/solutions/85bb.md +++ b/solutions/85bb.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [85bb](../questions/85bb): *String stack iterators* +## Solution to [85bb](../questions/85bb.md): *String stack iterators* See code at `solutions/code/tutorialquestions/question85bb` diff --git a/solutions/876b.md b/solutions/876b.md index cb51f36..893eb95 100644 --- a/solutions/876b.md +++ b/solutions/876b.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [876b](../questions/876b): *Generics and subclasses* +## Solution to [876b](../questions/876b.md): *Generics and subclasses* See code at `solutions/code/tutorialquestions/question876b` diff --git a/solutions/888a.md b/solutions/888a.md new file mode 100755 index 0000000..b1447c1 --- /dev/null +++ b/solutions/888a.md @@ -0,0 +1,11 @@ +[Back to questions](../README.md) + +## Solution to [888a](../questions/888a.md): *Generic methods with streams* + +See code at `solutions/code/tutorialquestions/question888a` + +Compare your solution with the code in the sample solution. + +The main thing to understand about the code for these questions is that generic type information for a method (e.g. of the form ``) comes *before* the return type of the method, and *after* any other keywords such as `static` or `public`. + +The sample implementation of `zip`, which uses `IntStream` and `mapToObj`, is worth studying carefully. \ No newline at end of file diff --git a/solutions/8a61.md b/solutions/8a61.md index 1f40821..972cc55 100644 --- a/solutions/8a61.md +++ b/solutions/8a61.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [8a61](../questions/8a61): *Int set* +## Solution to [8a61](../questions/8a61.md): *Int set* See code at `solutions/code/tutorialquestions/question8a61` diff --git a/solutions/8d24.md b/solutions/8d24.md index a2b910a..ef923b2 100644 --- a/solutions/8d24.md +++ b/solutions/8d24.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [8d24](../questions/8d24): *Lucky battling fighters* +## Solution to [8d24](../questions/8d24.md): *Lucky battling fighters* See code at `solutions/code/tutorialquestions/question8d24` diff --git a/solutions/8f65.md b/solutions/8f65.md index 9370b98..d5e74c5 100644 --- a/solutions/8f65.md +++ b/solutions/8f65.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [8f65](../questions/8f65): *Lucky battling fighters with inheritance* +## Solution to [8f65](../questions/8f65.md): *Lucky battling fighters with inheritance* See code at `solutions/code/tutorialquestions/question8f65` diff --git a/solutions/937d.md b/solutions/937d.md index a5e4d16..1e80921 100644 --- a/solutions/937d.md +++ b/solutions/937d.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [937d](../questions/937d): *Flawed rectangle* +## Solution to [937d](../questions/937d.md): *Flawed rectangle* See code at `solutions/code/tutorialquestions/question937d` diff --git a/solutions/96df.md b/solutions/96df.md index 23a6c72..5acefbc 100644 --- a/solutions/96df.md +++ b/solutions/96df.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [96df](../questions/96df): *Tree nodes* +## Solution to [96df](../questions/96df.md): *Tree nodes* See code at `solutions/code/tutorialquestions/question96df` diff --git a/solutions/98e3.md b/solutions/98e3.md index 204dd91..ee81d60 100755 --- a/solutions/98e3.md +++ b/solutions/98e3.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [98e3](../questions/98e3): *... 1 4 2 1 4 2 1 ...* +## Solution to [98e3](../questions/98e3.md): *... 1 4 2 1 4 2 1 ...* See code at `solutions/code/tutorialquestions/question98e3` diff --git a/solutions/9a9b.md b/solutions/9a9b.md index 5ba2248..b8ad4c8 100644 --- a/solutions/9a9b.md +++ b/solutions/9a9b.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [9a9b](../questions/9a9b): *Transposing tunes* +## Solution to [9a9b](../questions/9a9b.md): *Transposing tunes* See code at `solutions/code/tutorialquestions/question9a9b` diff --git a/solutions/a22c.md b/solutions/a22c.md index 59fdc07..daea6ff 100644 --- a/solutions/a22c.md +++ b/solutions/a22c.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [a22c](../questions/a22c): *No duplicate email addresses* +## Solution to [a22c](../questions/a22c.md): *No duplicate email addresses* See code at `solutions/code/tutorialquestions/questiona22c` diff --git a/solutions/a6e7.md b/solutions/a6e7.md index 0aab49c..4cd7b46 100644 --- a/solutions/a6e7.md +++ b/solutions/a6e7.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [a6e7](../questions/a6e7): *Int set iterators* +## Solution to [a6e7](../questions/a6e7.md): *Int set iterators* See code at `solutions/code/tutorialquestions/questiona6e7` diff --git a/solutions/aa68.md b/solutions/aa68.md index 0fa9576..351d81b 100644 --- a/solutions/aa68.md +++ b/solutions/aa68.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [aa68](../questions/aa68): *Symmetric equality testing* +## Solution to [aa68](../questions/aa68.md): *Symmetric equality testing* See code at `solutions/code/tutorialquestions/questionaa68` @@ -33,7 +33,6 @@ public boolean canEqual(Object that) { Note that it is *usually* bad practice to override a method and make no reference to `super`. This is an exception (though note that if the overridden version of `canEqual` returns *true*, the superclass version would be guaranteed to do the same). -The implementation of `equals` in `ColouredPoint` is now adapted analogously to how `equals` was adapted for `Point`: we check that the `ColouredPoint` on which `equals` is being invoked `canEqual` the incoming object. We then cast the incoming object to a `ColouredPoint`, and test whether this `ColouredPoint` `canEqual` the `ColouredPoint` on which `equals` is being invoked. Finally, we test superclass equality, and compare on the `colour` fields, as before. +The implementation of `equals` in `ColouredPoint` is now adapted analogously to how `equals` was adapted for `Point`: we check that the `ColouredPoint` on which `equals` is being invoked `canEqual` the incoming object. We then cast the incoming object to a `ColouredPoint` and test superclass equality. Due to the way we implemented `equals` in `Point`, this superclass call will test whether this `ColouredPoint` `canEqual` the `ColouredPoint` on which `equals` is being invoked. Finally, we compare on the `colour` fields, as before. The crucial missing property that `canEqual` has added is that if we compare a plain old `Point` with a `ColouredPoint` we are *guaranteed* to get the result `false`. Thus the asymmetry identified in [question 5235](../questions/5235.md) cannot occur. - diff --git a/solutions/b33f.md b/solutions/b33f.md new file mode 100755 index 0000000..4eccb20 --- /dev/null +++ b/solutions/b33f.md @@ -0,0 +1,11 @@ +[Back to questions](../README.md) + +## Solution to [b33f](../questions/b33f.md): *Logging using a functional interface* + +See code at `solutions/code/tutorialquestions/questionb33f` + +Compare the sample source code for this question with your solution. + +Notice the use of the `ifPresent` method of `Optional` in my implementation of `FileInspector`. This takes a *consumer* -- a void function whose argument is the element type of the optional, and can be used to perform an operation on the element of the optional if it exists. + +Notice also the use of the `@FunctionalInterface` annotation on the `Logger` and `StringInspector` interfaces. This annotation makes it illegal to add any more non-static, non-default methods to these interfaces, ensuring that it will always be possible to implement the interfaces concisely using lambdas. Think about why adding static or default methods is OK. \ No newline at end of file diff --git a/solutions/b401.md b/solutions/b401.md index 78195cf..0da9358 100644 --- a/solutions/b401.md +++ b/solutions/b401.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [b401](../questions/b401): *Generic sets* +## Solution to [b401](../questions/b401.md): *Generic sets* See code at `solutions/code/tutorialquestions/questionb401` diff --git a/solutions/b4a5.md b/solutions/b4a5.md index 57c4321..a23d866 100644 --- a/solutions/b4a5.md +++ b/solutions/b4a5.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [b4a5](../questions/b4a5): *Observing the garbage collector* +## Solution to [b4a5](../questions/b4a5.md): *Observing the garbage collector* See code at `solutions/code/tutorialquestions/questionb4a5` diff --git a/solutions/bdb4.md b/solutions/bdb4.md index 7c80da3..a587e45 100644 --- a/solutions/bdb4.md +++ b/solutions/bdb4.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [bdb4](../questions/bdb4): *Flawed house* +## Solution to [bdb4](../questions/bdb4.md): *Flawed house* See code at `solutions/code/tutorialquestions/questionbdb4` diff --git a/solutions/bec2.md b/solutions/bec2.md index 97bcfaf..1f448ec 100644 --- a/solutions/bec2.md +++ b/solutions/bec2.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [bec2](../questions/bec2): *Music collection* +## Solution to [bec2](../questions/bec2.md): *Music collection* See code at `solutions/code/tutorialquestions/questionbec2` diff --git a/solutions/c2b8.md b/solutions/c2b8.md index ff7f955..9b18a73 100644 --- a/solutions/c2b8.md +++ b/solutions/c2b8.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [c2b8](../questions/c2b8): *Irresponsible rectangle* +## Solution to [c2b8](../questions/c2b8.md): *Irresponsible rectangle* See code at `solutions/code/tutorialquestions/questionc2b8` diff --git a/solutions/c822.md b/solutions/c822.md index b3085bd..c3ed1e0 100644 --- a/solutions/c822.md +++ b/solutions/c822.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [c822](../questions/c822): *Problems cloning tree nodes* +## Solution to [c822](../questions/c822.md): *Problems cloning tree nodes* See code at `solutions/code/tutorialquestions/questionc822` diff --git a/solutions/code/tutorialquestions/question014e/RandomIntegers.java b/solutions/code/tutorialquestions/question014e/RandomIntegers.java index b268cf7..81d66a8 100755 --- a/solutions/code/tutorialquestions/question014e/RandomIntegers.java +++ b/solutions/code/tutorialquestions/question014e/RandomIntegers.java @@ -45,7 +45,7 @@ public static void main(String[] args) { } } - System.out.println(""); + System.out.println(); System.out.println("I had to generate " + numbersGenerated + " random numbers between 0 and " + (maxNumber - 1) + " to have produced all such numbers at least once."); diff --git a/solutions/code/tutorialquestions/question0c21/instanceofsolution/PropertyCollection.java b/solutions/code/tutorialquestions/question0c21/instanceofsolution/PropertyCollection.java index 4e18ceb..e9cddf8 100755 --- a/solutions/code/tutorialquestions/question0c21/instanceofsolution/PropertyCollection.java +++ b/solutions/code/tutorialquestions/question0c21/instanceofsolution/PropertyCollection.java @@ -6,10 +6,10 @@ public class PropertyCollection { - private Set properties; + private final Set properties; public PropertyCollection() { - properties = new HashSet(); + properties = new HashSet<>(); } public void addProperty(Property property) { @@ -17,7 +17,7 @@ public void addProperty(Property property) { } public Set getHouses() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p instanceof House) { result.add((House) p); @@ -27,7 +27,7 @@ public Set getHouses() { } public Set getBungalows() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p instanceof Bungalow) { result.add((Bungalow) p); @@ -37,7 +37,7 @@ public Set getBungalows() { } public Set getFlats() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p instanceof Flat) { result.add((Flat) p); @@ -47,7 +47,7 @@ public Set getFlats() { } public Set getMaisonettes() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p instanceof Maisonette) { result.add((Maisonette) p); @@ -57,7 +57,7 @@ public Set getMaisonettes() { } public Set getTerracedHouses() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p instanceof TerracedHouse) { result.add((TerracedHouse) p); diff --git a/solutions/code/tutorialquestions/question0c21/methodssolution/PropertyCollection.java b/solutions/code/tutorialquestions/question0c21/methodssolution/PropertyCollection.java index 321fa52..0158543 100755 --- a/solutions/code/tutorialquestions/question0c21/methodssolution/PropertyCollection.java +++ b/solutions/code/tutorialquestions/question0c21/methodssolution/PropertyCollection.java @@ -6,10 +6,10 @@ public class PropertyCollection { - private Set properties; + private final Set properties; public PropertyCollection() { - properties = new HashSet(); + properties = new HashSet<>(); } public void addProperty(Property property) { @@ -17,7 +17,7 @@ public void addProperty(Property property) { } public Set getHouses() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p.isHouse()) { result.add((House) p); @@ -27,7 +27,7 @@ public Set getHouses() { } public Set getBungalows() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p.isBungalow()) { result.add((Bungalow) p); @@ -37,7 +37,7 @@ public Set getBungalows() { } public Set getFlats() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p.isFlat()) { result.add((Flat) p); @@ -47,7 +47,7 @@ public Set getFlats() { } public Set getMaisonettes() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p.isMaisonette()) { result.add((Maisonette) p); @@ -57,7 +57,7 @@ public Set getMaisonettes() { } public Set getTerracedHouses() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (Property p : properties) { if (p.isTerraced()) { result.add((TerracedHouse) p); diff --git a/solutions/code/tutorialquestions/question1171/original/GraphNode.java b/solutions/code/tutorialquestions/question1171/original/GraphNode.java index fc44b7d..340bda2 100755 --- a/solutions/code/tutorialquestions/question1171/original/GraphNode.java +++ b/solutions/code/tutorialquestions/question1171/original/GraphNode.java @@ -6,10 +6,10 @@ public class GraphNode { private E key; - private List> successors; + private final List> successors; public GraphNode() { - successors = new ArrayList>(); + successors = new ArrayList<>(); } public int getNumberOfSuccessors() { diff --git a/solutions/code/tutorialquestions/question1171/solution/Demo.java b/solutions/code/tutorialquestions/question1171/solution/Demo.java index 2a9ff73..087597d 100755 --- a/solutions/code/tutorialquestions/question1171/solution/Demo.java +++ b/solutions/code/tutorialquestions/question1171/solution/Demo.java @@ -6,11 +6,11 @@ public class Demo { public static void main(String[] args) { // Make some nodes - GraphNode original = new GraphNode(); + GraphNode original = new GraphNode<>(); original.setKey("Hello"); - GraphNode child1 = new GraphNode(); + GraphNode child1 = new GraphNode<>(); child1.setKey("Child 1"); - GraphNode child2 = new GraphNode(); + GraphNode child2 = new GraphNode<>(); child1.setKey("Child 2"); // Join them up @@ -20,7 +20,7 @@ public static void main(String[] args) { child2.addSuccessor(original); // Creates a cycle // Clone original - GraphNode clone = (GraphNode) original.clone(); + GraphNode clone = original.clone(); // Check that the clone uses distinct nodes assert original != clone; diff --git a/solutions/code/tutorialquestions/question1171/solution/GraphNode.java b/solutions/code/tutorialquestions/question1171/solution/GraphNode.java index c086897..ddd7e92 100755 --- a/solutions/code/tutorialquestions/question1171/solution/GraphNode.java +++ b/solutions/code/tutorialquestions/question1171/solution/GraphNode.java @@ -13,7 +13,7 @@ public class GraphNode implements Cloneable { private List> successors; public GraphNode() { - successors = new ArrayList>(); + successors = new ArrayList<>(); } public int getNumberOfSuccessors() { @@ -39,9 +39,9 @@ public void setKey(E key) { @Override public GraphNode clone() { - Map, GraphNode> oldToNew = new HashMap, GraphNode>(); + Map, GraphNode> oldToNew = new HashMap<>(); - Deque> stack = new ArrayDeque>(); + Deque> stack = new ArrayDeque<>(); stack.push(this); @@ -70,7 +70,7 @@ public GraphNode clone() { private GraphNode internalClone() { try { GraphNode result = (GraphNode) super.clone(); - result.successors = new ArrayList>(); + result.successors = new ArrayList<>(); return result; } catch (CloneNotSupportedException ex) { // This should never be thrown, because diff --git a/solutions/code/tutorialquestions/question11e2/Example.java b/solutions/code/tutorialquestions/question11e2/Example.java new file mode 100755 index 0000000..5641b78 --- /dev/null +++ b/solutions/code/tutorialquestions/question11e2/Example.java @@ -0,0 +1,56 @@ +package tutorialquestions.question11e2; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +public class Example { + + public static > Optional + getSmallestCollection(List collections) { + return collections + .stream() + .reduce((collection1, collection2) -> + collection1.size() < collection2.size() ? collection1 : collection2); + } + + public static void main(String[] args) { + final Set s1 = Set.of(1, 2, 3, 4); + final Set s2 = Set.of(1, 2); + final Set s3 = Set.of(1, 2, 3, 4); + final Set s4 = Set.of(3, 4); + + final List l1 = new ArrayList<>(List.of("alpha", "beta", "gamma")); + final List l2 = new ArrayList<>(List.of("ay", "bee", "cee")); + final List l3 = new ArrayList<>(List.of("mouse", "fox", "owl", "snake", + "gruffalo")); + final List l4 = new ArrayList<>(List.of("dog", "cat", "frog", "bird", "witch", + "broomstick")); + final List l5 = new ArrayList<>(List.of("dragon", "pox")); + final List l6 = new ArrayList<>(List.of("dragon", "pox")); + + final List> listOfSetsOfIntegers = List.of(s1, s2, s3, s4); + final List> listOfListsOfStrings = List.of(l1, l2, l3, l4, l5, l6); + + // Think about why the following would not compile: + // final List> listOfCollections = List.of( + // s1, s2, s3, s4, l1, l2, l3, l4, l5); + final List> listOfCollections = List.of(s1, s2, s3, s4, l1, l2, l3, l4, l5); + + final Optional> smallestSet = getSmallestCollection(listOfSetsOfIntegers); + assert smallestSet.isPresent(); + assert smallestSet.get().size() == 2; + + final Optional> smallestList = getSmallestCollection(listOfListsOfStrings); + assert smallestList.isPresent(); + // Think about why '==' would *not* be OK here. + assert smallestList.get().equals(l5); + + // Think about why the following would not compile: + // final Optional> smallestCollection = getSmallestCollection(listOfCollections); + + } + +} diff --git a/solutions/code/tutorialquestions/question1486/StringStackArray.java b/solutions/code/tutorialquestions/question1486/StringStackArray.java index 6c04c29..b9cd00a 100755 --- a/solutions/code/tutorialquestions/question1486/StringStackArray.java +++ b/solutions/code/tutorialquestions/question1486/StringStackArray.java @@ -4,7 +4,7 @@ public class StringStackArray implements StringStack { private static final int STACK_LIMIT = 100; - private String[] elements; + private final String[] elements; private int stackPointer; public StringStackArray() { diff --git a/solutions/code/tutorialquestions/question1486/StringStackList.java b/solutions/code/tutorialquestions/question1486/StringStackList.java index b557a1c..6daa9e8 100755 --- a/solutions/code/tutorialquestions/question1486/StringStackList.java +++ b/solutions/code/tutorialquestions/question1486/StringStackList.java @@ -5,10 +5,10 @@ public class StringStackList implements StringStack { - private List elements; + private final List elements; public StringStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override diff --git a/solutions/code/tutorialquestions/question17b1/afterdefault/A.java b/solutions/code/tutorialquestions/question17b1/afterdefault/A.java new file mode 100755 index 0000000..869ed5a --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/afterdefault/A.java @@ -0,0 +1,29 @@ +package tutorialquestions.question17b1.afterdefault; + +public class A implements I { + @Override + public int foo() { + return 0; + } + + @Override + public int foo(int x) { + return 0; + } + + @Override + public int bar(int x) { + return 0; + } + + public int foobar() { + return 42; + } + + // This method had to be renamed to avoid a clash with I.foobar, which had the same name + // and parameter types but a different return type. + public void foobarOriginal(int x) { + System.out.println(x); + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/afterdefault/B.java b/solutions/code/tutorialquestions/question17b1/afterdefault/B.java new file mode 100755 index 0000000..e4c12d7 --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/afterdefault/B.java @@ -0,0 +1,26 @@ +package tutorialquestions.question17b1.afterdefault; + +public class B implements I, J { + @Override + public int foo() { + return 0; + } + + @Override + public int foo(int x) { + return 0; + } + + @Override + public int bar(int x) { + return 0; + } + + // This method had to be provided to avoid ambiguity between which of I.foobar and J.foobar + // would be called if foobar were invoked on an instance of B. This implementation chooses + // the version of foobar from I. + @Override + public int foobar(int x) { + return I.super.foobar(x); + } +} diff --git a/solutions/code/tutorialquestions/question17b1/afterdefault/C.java b/solutions/code/tutorialquestions/question17b1/afterdefault/C.java new file mode 100755 index 0000000..10fe815 --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/afterdefault/C.java @@ -0,0 +1,43 @@ +package tutorialquestions.question17b1.afterdefault; + +import java.io.IOException; + +public class C implements K { + @Override + public void baz() { + + } + + @Override + public int foo() { + return 0; + } + + @Override + public int foo(int x) { + return 0; + } + + @Override + public int bar(int x) { + return 0; + } + + // This method had to be renamed because the default zero-argument foobar from I does not + // specify that it might throw an exception, and thus clients that invoke that method would not + // expect a checked exception to be thrown. It is illegal to increase the extent to which + // exceptions are thrown when overriding or implementing a method from a superclass or + // interface. + public int foobarOriginal() throws IOException { + throw new IOException(); + } + + // This method had to be renamed because I and J provide implicitly *public* default + // implementations of foobar with this signature. It is illegal to decrease the visibility of + // a method from a superclass or interface when overriding or implementing it; this method has + // protected visibility. + protected int foobarOriginal(int x) { + return x; + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/afterdefault/I.java b/solutions/code/tutorialquestions/question17b1/afterdefault/I.java new file mode 100755 index 0000000..09763a0 --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/afterdefault/I.java @@ -0,0 +1,19 @@ +package tutorialquestions.question17b1.afterdefault; + +public interface I { + + int foo(); + + int foo(int x); + + int bar(int x); + + default int foobar() { + return bar(foo()); + } + + default int foobar(int x) { + return bar(foo(x)); + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/afterdefault/J.java b/solutions/code/tutorialquestions/question17b1/afterdefault/J.java new file mode 100755 index 0000000..e4e0c3d --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/afterdefault/J.java @@ -0,0 +1,13 @@ +package tutorialquestions.question17b1.afterdefault; + +public interface J { + + int foo(int x); + + int bar(int y); + + default int foobar(int x) { + return bar(foo(x)); + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/afterdefault/K.java b/solutions/code/tutorialquestions/question17b1/afterdefault/K.java new file mode 100755 index 0000000..604da9f --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/afterdefault/K.java @@ -0,0 +1,11 @@ +package tutorialquestions.question17b1.afterdefault; + +public interface K extends I, J { + + void baz(); + + default int foobar(int x) { + return I.super.foobar(x); + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/beforedefault/A.java b/solutions/code/tutorialquestions/question17b1/beforedefault/A.java new file mode 100755 index 0000000..fbaad9d --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/beforedefault/A.java @@ -0,0 +1,27 @@ +package tutorialquestions.question17b1.beforedefault; + +public class A implements I { + @Override + public int foo() { + return 0; + } + + @Override + public int foo(int x) { + return 0; + } + + @Override + public int bar(int x) { + return 0; + } + + public int foobar() { + return 42; + } + + public void foobar(int x) { + System.out.println(x); + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/beforedefault/B.java b/solutions/code/tutorialquestions/question17b1/beforedefault/B.java new file mode 100755 index 0000000..f253dc7 --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/beforedefault/B.java @@ -0,0 +1,19 @@ +package tutorialquestions.question17b1.beforedefault; + +public class B implements I, J { + @Override + public int foo() { + return 0; + } + + @Override + public int foo(int x) { + return 0; + } + + @Override + public int bar(int x) { + return 0; + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/beforedefault/C.java b/solutions/code/tutorialquestions/question17b1/beforedefault/C.java new file mode 100755 index 0000000..55fad00 --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/beforedefault/C.java @@ -0,0 +1,34 @@ +package tutorialquestions.question17b1.beforedefault; + +import java.io.IOException; + +public class C implements K { + @Override + public void baz() { + + } + + @Override + public int foo() { + return 0; + } + + @Override + public int foo(int x) { + return 0; + } + + @Override + public int bar(int x) { + return 0; + } + + public int foobar() throws IOException { + throw new IOException(); + } + + protected int foobar(int x) { + return x; + } + +} diff --git a/solutions/code/tutorialquestions/question17b1/beforedefault/I.java b/solutions/code/tutorialquestions/question17b1/beforedefault/I.java new file mode 100755 index 0000000..dc6134a --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/beforedefault/I.java @@ -0,0 +1,11 @@ +package tutorialquestions.question17b1.beforedefault; + +public interface I { + + int foo(); + + int foo(int x); + + int bar(int x); + +} diff --git a/solutions/code/tutorialquestions/question17b1/beforedefault/J.java b/solutions/code/tutorialquestions/question17b1/beforedefault/J.java new file mode 100755 index 0000000..9f2ddbe --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/beforedefault/J.java @@ -0,0 +1,9 @@ +package tutorialquestions.question17b1.beforedefault; + +public interface J { + + int foo(int x); + + int bar(int y); + +} diff --git a/solutions/code/tutorialquestions/question17b1/beforedefault/K.java b/solutions/code/tutorialquestions/question17b1/beforedefault/K.java new file mode 100755 index 0000000..7e4c254 --- /dev/null +++ b/solutions/code/tutorialquestions/question17b1/beforedefault/K.java @@ -0,0 +1,7 @@ +package tutorialquestions.question17b1.beforedefault; + +public interface K extends I, J { + + void baz(); + +} diff --git a/solutions/code/tutorialquestions/question1ae9/objectpool/Demo.java b/solutions/code/tutorialquestions/question1ae9/objectpool/Demo.java index 612599d..db1c944 100755 --- a/solutions/code/tutorialquestions/question1ae9/objectpool/Demo.java +++ b/solutions/code/tutorialquestions/question1ae9/objectpool/Demo.java @@ -7,7 +7,7 @@ public class Demo { public static void main(String[] args) { - List pointList = new ArrayList(); + List pointList = new ArrayList<>(); for (int i = 0; i < 10; i++) { pointList.add(Point.makePoint(0, 0, 0)); diff --git a/solutions/code/tutorialquestions/question1ae9/objectpool/Point.java b/solutions/code/tutorialquestions/question1ae9/objectpool/Point.java index 74944e3..fd6ba45 100755 --- a/solutions/code/tutorialquestions/question1ae9/objectpool/Point.java +++ b/solutions/code/tutorialquestions/question1ae9/objectpool/Point.java @@ -9,7 +9,7 @@ public class Point { private final int coordY; private final int coordZ; - private static Map pool = new HashMap(); + private static final Map pool = new HashMap<>(); private Point(int coordX, int coordY, int coordZ) { this.coordX = coordX; @@ -42,9 +42,9 @@ public boolean equals(Object that) { @Override public int hashCode() { - return new Integer(coordX).hashCode() - ^ new Integer(coordY).hashCode() - ^ new Integer(coordZ).hashCode(); + return Integer.valueOf(coordX).hashCode() + ^ Integer.valueOf(coordY).hashCode() + ^ Integer.valueOf(coordZ).hashCode(); } } diff --git a/solutions/code/tutorialquestions/question1ae9/original/Demo.java b/solutions/code/tutorialquestions/question1ae9/original/Demo.java index 21222f2..4975409 100755 --- a/solutions/code/tutorialquestions/question1ae9/original/Demo.java +++ b/solutions/code/tutorialquestions/question1ae9/original/Demo.java @@ -7,7 +7,7 @@ public class Demo { public static void main(String[] args) { - List pointList = new ArrayList(); + List pointList = new ArrayList<>(); for (int i = 0; i < 10; i++) { pointList.add(new Point(0, 0, 0)); diff --git a/solutions/code/tutorialquestions/question1ae9/original/Point.java b/solutions/code/tutorialquestions/question1ae9/original/Point.java index 5d813c8..ed63139 100755 --- a/solutions/code/tutorialquestions/question1ae9/original/Point.java +++ b/solutions/code/tutorialquestions/question1ae9/original/Point.java @@ -27,9 +27,9 @@ public boolean equals(Object that) { @Override public int hashCode() { - return new Integer(coordX).hashCode() - ^ new Integer(coordY).hashCode() - ^ new Integer(coordZ).hashCode(); + return Integer.valueOf(coordX).hashCode() + ^ Integer.valueOf(coordY).hashCode() + ^ Integer.valueOf(coordZ).hashCode(); } } diff --git a/solutions/code/tutorialquestions/question1aeb/NumberManipulator.java b/solutions/code/tutorialquestions/question1aeb/NumberManipulator.java index da28a9d..96b1ca0 100755 --- a/solutions/code/tutorialquestions/question1aeb/NumberManipulator.java +++ b/solutions/code/tutorialquestions/question1aeb/NumberManipulator.java @@ -12,7 +12,7 @@ public class NumberManipulator { public static Set readNumbers(int count, NumberParser parser) throws IOException { - Set result = new HashSet(); + Set result = new HashSet<>(); BufferedReader br = new BufferedReader( new InputStreamReader( diff --git a/solutions/code/tutorialquestions/question290b/weakreferences/Point.java b/solutions/code/tutorialquestions/question290b/weakreferences/Point.java index 087a37e..fd0a791 100755 --- a/solutions/code/tutorialquestions/question290b/weakreferences/Point.java +++ b/solutions/code/tutorialquestions/question290b/weakreferences/Point.java @@ -10,7 +10,7 @@ public class Point { private final int coordY; private final int coordZ; - private static Map> pool = new WeakHashMap<>(); + private static final Map> pool = new WeakHashMap<>(); private Point(int coordX, int coordY, int coordZ) { this.coordX = coordX; @@ -27,7 +27,7 @@ public static Point makePoint(int coordX, int coordY, int coordZ) { return pool.get(point).get(); // point will now be garbage collected } - pool.put(point, new WeakReference(point)); + pool.put(point, new WeakReference<>(point)); return point; } @@ -38,8 +38,7 @@ public String toString() { @Override public boolean equals(Object that) { - return that != null - && that instanceof Point + return that instanceof Point && coordX == ((Point) that).coordX && coordY == ((Point) that).coordY && coordZ == ((Point) that).coordZ; @@ -47,9 +46,9 @@ public boolean equals(Object that) { @Override public int hashCode() { - return new Integer(coordX).hashCode() - ^ new Integer(coordY).hashCode() - ^ new Integer(coordZ).hashCode(); + return Integer.valueOf(coordX).hashCode() + ^ Integer.valueOf(coordY).hashCode() + ^ Integer.valueOf(coordZ).hashCode(); } /** diff --git a/solutions/code/tutorialquestions/question2d33/ReversedOrderOfInputStack.java b/solutions/code/tutorialquestions/question2d33/ReversedOrderOfInputStack.java index e80decb..521276a 100755 --- a/solutions/code/tutorialquestions/question2d33/ReversedOrderOfInputStack.java +++ b/solutions/code/tutorialquestions/question2d33/ReversedOrderOfInputStack.java @@ -13,9 +13,9 @@ public class ReversedOrderOfInputStack { */ public static void main(String[] args) throws IOException { - Deque dq = new ArrayDeque<>(); + final Deque dq = new ArrayDeque<>(); - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = br.readLine(); diff --git a/solutions/code/tutorialquestions/question2ffc/Demo.java b/solutions/code/tutorialquestions/question2ffc/Demo.java index 7b46d1e..0a4675f 100755 --- a/solutions/code/tutorialquestions/question2ffc/Demo.java +++ b/solutions/code/tutorialquestions/question2ffc/Demo.java @@ -10,9 +10,9 @@ public static void transferStacks(GenericStack dest, GenericStack src) public static void main(String[] args) { - final GenericStack first = new GenericStackArray(); + final GenericStack first = new GenericStackArray<>(); - final GenericStack second = new GenericStackList(); + final GenericStack second = new GenericStackList<>(); first.push("The"); first.push("quick"); diff --git a/solutions/code/tutorialquestions/question2ffc/GenericStackArray.java b/solutions/code/tutorialquestions/question2ffc/GenericStackArray.java index e2ef302..7d8c7e6 100755 --- a/solutions/code/tutorialquestions/question2ffc/GenericStackArray.java +++ b/solutions/code/tutorialquestions/question2ffc/GenericStackArray.java @@ -4,7 +4,7 @@ public class GenericStackArray implements GenericStack { private static final int STACK_LIMIT = 100; - private E[] elements; + private final E[] elements; private int stackPointer; @SuppressWarnings("unchecked") diff --git a/solutions/code/tutorialquestions/question2ffc/GenericStackList.java b/solutions/code/tutorialquestions/question2ffc/GenericStackList.java index 96c10c6..68bd4bb 100755 --- a/solutions/code/tutorialquestions/question2ffc/GenericStackList.java +++ b/solutions/code/tutorialquestions/question2ffc/GenericStackList.java @@ -5,10 +5,10 @@ public class GenericStackList implements GenericStack { - private List elements; + private final List elements; public GenericStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override diff --git a/solutions/code/tutorialquestions/question30cd/HeapExhaustion.java b/solutions/code/tutorialquestions/question30cd/HeapExhaustion.java index 5aa55e0..9a66331 100755 --- a/solutions/code/tutorialquestions/question30cd/HeapExhaustion.java +++ b/solutions/code/tutorialquestions/question30cd/HeapExhaustion.java @@ -7,11 +7,12 @@ public class HeapExhaustion { public static void main(String[] args) { - List infiniteList = new ArrayList(); + final List infiniteList = new ArrayList<>(); try { + //noinspection InfiniteLoopStatement while (true) { - infiniteList.add(new Integer(0)); + infiniteList.add(0); } } catch (OutOfMemoryError exception) { System.out.println("Length of list before memory exhausted: " + infiniteList.size()); diff --git a/solutions/code/tutorialquestions/question336b/Demo.java b/solutions/code/tutorialquestions/question336b/Demo.java new file mode 100755 index 0000000..4b781dc --- /dev/null +++ b/solutions/code/tutorialquestions/question336b/Demo.java @@ -0,0 +1,59 @@ +package tutorialquestions.question336b; + + +import java.util.List; + +public class Demo { + + private static final int MEDIUM_NUMBER = 10000; + private static final int LARGE_NUMBER = 1000000; + + public static void main(String[] args) { + + final GenericSet set1 = new MemoryEfficientGenericSet<>(); + + final GenericSet set2 = new SpeedEfficientGenericSet<>(); + + for (int i = 0; i < MEDIUM_NUMBER; i++) { + set1.add(i); + set2.add(i); + } + + final Integer[] lotsOfDuplicates = new Integer[LARGE_NUMBER]; + for (int i = 0; i < LARGE_NUMBER; i++) { + // Add LARGE_NUMBER or (LARGE_NUMBER + 1) at position i of the array, depending on the parity + // of i. + lotsOfDuplicates[i] = LARGE_NUMBER + (i % 2); + } + + set1.addAll(lotsOfDuplicates); + set2.addAll(lotsOfDuplicates); + + for (GenericSet set : List.of(set1, set2)) { + if (!set.contains(LARGE_NUMBER) || !set.contains(LARGE_NUMBER + 1)) { + throw new AssertionError("Expected the set to contain " + LARGE_NUMBER); + } + + if (!set.asUnmodifiableSet().contains(LARGE_NUMBER) + || !set.asUnmodifiableSet().contains(LARGE_NUMBER + 1)) { + throw new AssertionError("An unmodifiable version of the set should still contain these" + + " elements"); + } + + try { + set.asUnmodifiableSet().add(2); + throw new AssertionError("Attempting to add to an unmodifiable set should have failed."); + } catch (UnsupportedOperationException exception1) { + // Good - an exception should have been thrown. + try { + set.asUnmodifiableSet().addAll(lotsOfDuplicates); + throw new AssertionError("Attempting to add to an unmodifiable set should have failed."); + } catch (UnsupportedOperationException exception2) { + // Good - an exception should also have been thrown, due to the default implementation of + // 'addAll' invoking 'add'. + } + } + } + } + +} diff --git a/solutions/code/tutorialquestions/question336b/GenericSet.java b/solutions/code/tutorialquestions/question336b/GenericSet.java new file mode 100755 index 0000000..da4a8cb --- /dev/null +++ b/solutions/code/tutorialquestions/question336b/GenericSet.java @@ -0,0 +1,60 @@ +package tutorialquestions.question336b; + +public interface GenericSet { + + void add(E item); + + boolean remove(E item); + + boolean isEmpty(); + + boolean contains(E item); + + // This is a vanilla method for adding every element in an array to the set, regardless of what + // the underlying set representation is. This might end up being very efficient for some set + // representations, but it is functionally correct. + default void addAll(E[] items) { + for (E item : items) { + add(item); + } + } + + // This returns a wrapper object that implements the GenericSet interface and throws an exception + // if either of the mutator methods are called. For the other methods, it delegates to the + // original set's methods. Think about what happens if you call one of the default methods on + // the set returned by 'asUnmodifiableSet'. + default GenericSet asUnmodifiableSet() { + + // This is an example of an *anonymous class* that implements the GenericSet interface. An + // alternative to using an anonymous class would be to have a generic class called + // UnmodifiableWrapperSet that implements the GenericSet interface and provides this + // functionality. + return new GenericSet<>() { + @Override + public void add(E item) { + throw new UnsupportedOperationException("Attempt to add to an unmodifiable set."); + } + + @Override + public boolean remove(E item) { + throw new UnsupportedOperationException("Attempt to remove from an unmodifiable set."); + } + + @Override + public boolean isEmpty() { + // Interesting syntax: if we just wrote "return isEmpty()" that would invoke the "isEmpty" + // method on the anonymous inner class, i.e. the current method, leading to infinite + // recursion. By writing "GenericSet.this" we ask for the outer class's version of the + // method to be invoked. + return GenericSet.this.isEmpty(); + } + + @Override + public boolean contains(E item) { + // See note above about this syntax. + return GenericSet.this.contains(item); + } + }; + } + +} diff --git a/solutions/code/tutorialquestions/question336b/MemoryEfficientGenericSet.java b/solutions/code/tutorialquestions/question336b/MemoryEfficientGenericSet.java new file mode 100755 index 0000000..60b04dd --- /dev/null +++ b/solutions/code/tutorialquestions/question336b/MemoryEfficientGenericSet.java @@ -0,0 +1,62 @@ +package tutorialquestions.question336b; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class MemoryEfficientGenericSet implements GenericSet { + + private final List elements; + + public MemoryEfficientGenericSet() { + elements = new ArrayList<>(); + } + + @Override + public void add(E item) { + if (elements.contains(item)) { + return; + } + elements.add(item); + } + + @Override + public boolean contains(E item) { + return elements.contains(item); + } + + @Override + public boolean isEmpty() { + return elements.isEmpty(); + } + + @Override + public boolean remove(E item) { + return elements.remove(item); + } + + // This overrides the default implementation of addAll to do something more efficient for + // this kind of set. + @Override + public void addAll(E[] items) { + // Keep track of all the elements that are known to belong to this set, storing them as a + // HashSet, which supports efficient lookup. + final Set knownElements = new HashSet<>(elements); + // Now go through all of the items to be added to our memory-efficient set. + for (E item : items) { + // Efficiently check whether we know this element already exists. If it does, + // do nothing. + if (!knownElements.contains(item)) { + // The element is new, so: + // (1) Add it directly to the end of 'elements' - don't go through our 'add' method, which + // would check (inefficiently) whether the element is already present. + elements.add(item); + // (2) Record the fact that we have seen this element, so that if it occurs in 'elements' + // again we skip it. + knownElements.add(item); + } + } + } + +} diff --git a/solutions/code/tutorialquestions/question336b/SpeedEfficientGenericSet.java b/solutions/code/tutorialquestions/question336b/SpeedEfficientGenericSet.java new file mode 100755 index 0000000..0b4799e --- /dev/null +++ b/solutions/code/tutorialquestions/question336b/SpeedEfficientGenericSet.java @@ -0,0 +1,34 @@ +package tutorialquestions.question336b; + +import java.util.HashSet; +import java.util.Set; + +public class SpeedEfficientGenericSet implements GenericSet { + + private final Set elements; + + public SpeedEfficientGenericSet() { + elements = new HashSet<>(); + } + + @Override + public void add(E item) { + elements.add(item); + } + + @Override + public boolean contains(E item) { + return elements.contains(item); + } + + @Override + public boolean isEmpty() { + return elements.isEmpty(); + } + + @Override + public boolean remove(E item) { + return elements.remove(item); + } + +} diff --git a/solutions/code/tutorialquestions/question4c70/Lottery.java b/solutions/code/tutorialquestions/question4c70/Lottery.java index acb699b..fee6625 100755 --- a/solutions/code/tutorialquestions/question4c70/Lottery.java +++ b/solutions/code/tutorialquestions/question4c70/Lottery.java @@ -10,11 +10,11 @@ public class Lottery { private static boolean numberAlreadyChosen(int[] numbers, int numChosenSoFar, int candidate) { + + assert numChosenSoFar < numbers.length; for (int i = 0; i < numChosenSoFar; i++) { - assert numChosenSoFar < numbers.length; - if (numbers[i] == candidate) { return true; @@ -60,4 +60,4 @@ public static void main(String[] args) { } -} \ No newline at end of file +} diff --git a/solutions/code/tutorialquestions/question5566/StringStackArray.java b/solutions/code/tutorialquestions/question5566/StringStackArray.java index 5353180..78de1f7 100755 --- a/solutions/code/tutorialquestions/question5566/StringStackArray.java +++ b/solutions/code/tutorialquestions/question5566/StringStackArray.java @@ -4,7 +4,7 @@ public class StringStackArray implements StringStack { private static final int STACK_LIMIT = 100; - private String[] elements; + private final String[] elements; private int stackPointer; public StringStackArray() { diff --git a/solutions/code/tutorialquestions/question5566/StringStackList.java b/solutions/code/tutorialquestions/question5566/StringStackList.java index 05267fa..cdebd98 100755 --- a/solutions/code/tutorialquestions/question5566/StringStackList.java +++ b/solutions/code/tutorialquestions/question5566/StringStackList.java @@ -5,10 +5,10 @@ public class StringStackList implements StringStack { - private List elements; + private final List elements; public StringStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override diff --git a/solutions/code/tutorialquestions/question5981/baddesign1/Shape.java b/solutions/code/tutorialquestions/question5981/baddesign1/Shape.java index 479fa87..38e6811 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign1/Shape.java +++ b/solutions/code/tutorialquestions/question5981/baddesign1/Shape.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign1; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Shape { // Represents semi-major axis if shape is an Ellipse, @@ -19,7 +16,7 @@ public class Shape { // Ignored if shape is a Circle or Square private int second; - private ShapeType type; + private final ShapeType type; public Shape(int first, int second, ShapeType type) { this.first = first; diff --git a/solutions/code/tutorialquestions/question5981/baddesign1/ShapeType.java b/solutions/code/tutorialquestions/question5981/baddesign1/ShapeType.java index 718e364..b1ed972 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign1/ShapeType.java +++ b/solutions/code/tutorialquestions/question5981/baddesign1/ShapeType.java @@ -1,5 +1,5 @@ package tutorialquestions.question5981.baddesign1; public enum ShapeType { - Ellipse, Circle, Rectangle, Square; + Ellipse, Circle, Rectangle, Square } diff --git a/solutions/code/tutorialquestions/question5981/baddesign2/Circle.java b/solutions/code/tutorialquestions/question5981/baddesign2/Circle.java index b2065c8..5c9b58a 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign2/Circle.java +++ b/solutions/code/tutorialquestions/question5981/baddesign2/Circle.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign2; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Circle extends Ellipse { public Circle(int radius) { diff --git a/solutions/code/tutorialquestions/question5981/baddesign2/Ellipse.java b/solutions/code/tutorialquestions/question5981/baddesign2/Ellipse.java index 2dabd21..ac10702 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign2/Ellipse.java +++ b/solutions/code/tutorialquestions/question5981/baddesign2/Ellipse.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign2; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Ellipse extends Shape { private int semiMajorAxis; diff --git a/solutions/code/tutorialquestions/question5981/baddesign2/Rectangle.java b/solutions/code/tutorialquestions/question5981/baddesign2/Rectangle.java index 90ef1fb..02236da 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign2/Rectangle.java +++ b/solutions/code/tutorialquestions/question5981/baddesign2/Rectangle.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign2; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Rectangle extends Shape { private int width; diff --git a/solutions/code/tutorialquestions/question5981/baddesign2/Shape.java b/solutions/code/tutorialquestions/question5981/baddesign2/Shape.java index 5a5168e..2ed00b2 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign2/Shape.java +++ b/solutions/code/tutorialquestions/question5981/baddesign2/Shape.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign2; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public abstract class Shape { } diff --git a/solutions/code/tutorialquestions/question5981/baddesign2/Square.java b/solutions/code/tutorialquestions/question5981/baddesign2/Square.java index dc56ba3..b5e158b 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign2/Square.java +++ b/solutions/code/tutorialquestions/question5981/baddesign2/Square.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign2; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Square extends Rectangle { public Square(int side) { diff --git a/solutions/code/tutorialquestions/question5981/baddesign3/Ellipse.java b/solutions/code/tutorialquestions/question5981/baddesign3/Ellipse.java index 474db4c..6ba28e5 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign3/Ellipse.java +++ b/solutions/code/tutorialquestions/question5981/baddesign3/Ellipse.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign3; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Ellipse extends Shape { public Ellipse(int semiMajorAxis, int semiMinorAxis) { diff --git a/solutions/code/tutorialquestions/question5981/baddesign3/Rectangle.java b/solutions/code/tutorialquestions/question5981/baddesign3/Rectangle.java index ebf46e7..ea2f28f 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign3/Rectangle.java +++ b/solutions/code/tutorialquestions/question5981/baddesign3/Rectangle.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign3; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public class Rectangle extends Shape { public Rectangle(int width, int height) { diff --git a/solutions/code/tutorialquestions/question5981/baddesign3/Shape.java b/solutions/code/tutorialquestions/question5981/baddesign3/Shape.java index f13f2a1..57b4428 100755 --- a/solutions/code/tutorialquestions/question5981/baddesign3/Shape.java +++ b/solutions/code/tutorialquestions/question5981/baddesign3/Shape.java @@ -1,12 +1,9 @@ -/***************************************************/ -/* This class illustrates a POOR DESIGN - * for the shapes question - * - * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! - ***************************************************/ - package tutorialquestions.question5981.baddesign3; +/** + * This class illustrates a POOR DESIGN for the shapes question. + * DO NOT CONFUSE THIS WITH THE SAMPLE SOLUTION!!! + */ public abstract class Shape { protected int widthOrSemimajorAxis; diff --git a/solutions/code/tutorialquestions/question5d30/UnreliableBufferedReader.java b/solutions/code/tutorialquestions/question5d30/UnreliableBufferedReader.java index d676417..8bfdefb 100755 --- a/solutions/code/tutorialquestions/question5d30/UnreliableBufferedReader.java +++ b/solutions/code/tutorialquestions/question5d30/UnreliableBufferedReader.java @@ -7,9 +7,9 @@ public class UnreliableBufferedReader extends BufferedReader { - private double probabilityOfError; + private final double probabilityOfError; - private Random generator; + private final Random generator; /** * Makes an unreliable reader from the given input stream reader with given probability of error. diff --git a/solutions/code/tutorialquestions/question6346/AddExpr.java b/solutions/code/tutorialquestions/question6346/AddExpr.java index 0a8d53a..1dff402 100755 --- a/solutions/code/tutorialquestions/question6346/AddExpr.java +++ b/solutions/code/tutorialquestions/question6346/AddExpr.java @@ -2,8 +2,8 @@ public class AddExpr implements Expr { - private Expr lhs; - private Expr rhs; + private final Expr lhs; + private final Expr rhs; public AddExpr(Expr lhs, Expr rhs) { this.lhs = lhs; diff --git a/solutions/code/tutorialquestions/question6346/FactExpr.java b/solutions/code/tutorialquestions/question6346/FactExpr.java index d788c57..6a8c03e 100755 --- a/solutions/code/tutorialquestions/question6346/FactExpr.java +++ b/solutions/code/tutorialquestions/question6346/FactExpr.java @@ -2,7 +2,7 @@ public class FactExpr implements Expr { - private Expr operand; + private final Expr operand; public FactExpr(Expr operand) { this.operand = operand; diff --git a/solutions/code/tutorialquestions/question6346/LiteralExpr.java b/solutions/code/tutorialquestions/question6346/LiteralExpr.java index 615242d..3c075cd 100755 --- a/solutions/code/tutorialquestions/question6346/LiteralExpr.java +++ b/solutions/code/tutorialquestions/question6346/LiteralExpr.java @@ -2,7 +2,7 @@ public class LiteralExpr implements Expr { - private int value; + private final int value; public LiteralExpr(int value) { this.value = value; diff --git a/solutions/code/tutorialquestions/question6346/MulExpr.java b/solutions/code/tutorialquestions/question6346/MulExpr.java index fed29d1..bfb752c 100755 --- a/solutions/code/tutorialquestions/question6346/MulExpr.java +++ b/solutions/code/tutorialquestions/question6346/MulExpr.java @@ -2,8 +2,8 @@ public class MulExpr implements Expr { - private Expr lhs; - private Expr rhs; + private final Expr lhs; + private final Expr rhs; public MulExpr(Expr lhs, Expr rhs) { this.lhs = lhs; diff --git a/solutions/code/tutorialquestions/question68e6/Example.java b/solutions/code/tutorialquestions/question68e6/Example.java new file mode 100755 index 0000000..1732fb8 --- /dev/null +++ b/solutions/code/tutorialquestions/question68e6/Example.java @@ -0,0 +1,85 @@ +package tutorialquestions.question68e6; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class Example { + + static List concatenate(List> lists) { + return lists + .stream() + .reduce(Collections.emptyList(), + (first, second) -> { + List result = new ArrayList<>(first); + result.addAll(second); + return result; + }); + } + + static int findMin(List numbers) { + return numbers + .stream() + .reduce(Integer.MAX_VALUE, Math::min); + } + + static int findMinOrZero(List numbers) { + return numbers + .stream() + .reduce(Math::min) + .orElse(0); + } + + static int findMax(List numbers) { + return numbers + .stream() + .reduce(Integer.MIN_VALUE, (first, second) -> Math.max(first, second)); + } + + static int findMaxOrZero(List numbers) { + return numbers + .stream() + .reduce((first, second) -> Math.max(first, second)) + .orElse(0); + } + + static int findMinOfMaxes(List> listOfLists) { + return findMin(listOfLists + .stream() + .map(Example::findMax) + .collect(Collectors.toList())); + } + + public static void main(String[] args) { + final List list1 = List.of(1, 2, 3, 4, 5, 9); + final List list2 = List.of(1, 10, 100, 1000, 10000); + final List list3 = List.of(6, 7, 8); + final List> listOfLists = List.of(list1, list2, list3); + + final List allIntegers = concatenate(listOfLists); + final int maxList1 = findMax(list1); + final int minList2 = findMin(list2); + final int maxEmpty = findMax(Collections.emptyList()); + final int minEmpty = findMin(Collections.emptyList()); + final int maxOrZeroEmpty = findMinOrZero(Collections.emptyList()); + final int minOrZeroEmpty = findMaxOrZero(Collections.emptyList()); + final int minOfMaxes = findMinOfMaxes(listOfLists); + final int minOfMaxesEmpty = findMinOfMaxes(Collections.emptyList()); + final int minOfMaxesListOfEmptyLists = findMinOfMaxes( + List.of(Collections.emptyList(), Collections.emptyList())); + + System.out.println("Concatenation of all the integer lists: " + allIntegers); + System.out.println("Max of list 1: " + maxList1); + System.out.println("Min of list 2: " + minList2); + System.out.println("Max of empty list: " + maxEmpty); + System.out.println("Min of empty list: " + minEmpty); + System.out.println("Max-or-zero of empty list: " + maxOrZeroEmpty); + System.out.println("Min-or-zero of empty list: " + minOrZeroEmpty); + System.out.println("Min of maxes: " + minOfMaxes); + System.out.println("Min of maxes of empty list: " + minOfMaxesEmpty); + System.out.println("Min of maxes of list of empty lists: " + minOfMaxesListOfEmptyLists); + + } + +} diff --git a/solutions/code/tutorialquestions/question7041/TreeNode.java b/solutions/code/tutorialquestions/question7041/TreeNode.java index 39e49f9..043984c 100755 --- a/solutions/code/tutorialquestions/question7041/TreeNode.java +++ b/solutions/code/tutorialquestions/question7041/TreeNode.java @@ -3,7 +3,7 @@ public class TreeNode { private E key; - private TreeNode[] children; + private final TreeNode[] children; @SuppressWarnings("unchecked") public TreeNode(int numberOfChildren) { @@ -31,7 +31,7 @@ public void setKey(E key) { } public TreeNode clone() { - TreeNode result = new TreeNode(getNumberOfChildren()); + TreeNode result = new TreeNode<>(getNumberOfChildren()); result.setKey(getKey()); for (int i = 0; i < getNumberOfChildren(); i++) { result.setChild(i, getChild(i).clone()); diff --git a/solutions/code/tutorialquestions/question710c/hashcode/Point.java b/solutions/code/tutorialquestions/question710c/hashcode/Point.java index 72950e1..873c503 100755 --- a/solutions/code/tutorialquestions/question710c/hashcode/Point.java +++ b/solutions/code/tutorialquestions/question710c/hashcode/Point.java @@ -49,8 +49,8 @@ public boolean equals(Object that) { @Override public int hashCode() { - return new Double(coordX).hashCode() ^ new Double(coordY).hashCode() - ^ new Double(coordZ).hashCode(); + return Double.valueOf(coordX).hashCode() ^ Double.valueOf(coordY).hashCode() + ^ Double.valueOf(coordZ).hashCode(); } diff --git a/solutions/code/tutorialquestions/question710c/hashcode/PointHashCodeDemo.java b/solutions/code/tutorialquestions/question710c/hashcode/PointHashCodeDemo.java index dab2c6d..6d315e9 100755 --- a/solutions/code/tutorialquestions/question710c/hashcode/PointHashCodeDemo.java +++ b/solutions/code/tutorialquestions/question710c/hashcode/PointHashCodeDemo.java @@ -17,7 +17,7 @@ public static void main(String[] args) { final Point firstColoured = new ColouredPoint(1.2, 2.3, 3.4, Colour.RED); final Point secondColoured = new ColouredPoint(1.2, 2.3, 3.4, Colour.RED); - Set pointSet = new HashSet(); + Set pointSet = new HashSet<>(); pointSet.add(first); diff --git a/solutions/code/tutorialquestions/question710c/nohashcode/PointHashCodeDemo.java b/solutions/code/tutorialquestions/question710c/nohashcode/PointHashCodeDemo.java index 3dde164..357978c 100755 --- a/solutions/code/tutorialquestions/question710c/nohashcode/PointHashCodeDemo.java +++ b/solutions/code/tutorialquestions/question710c/nohashcode/PointHashCodeDemo.java @@ -11,7 +11,7 @@ public static void main(String[] args) { Point first = new Point(1.2, 2.3, 3.4); Point second = new Point(1.2, 2.3, 3.4); - Set pointSet = new HashSet(); + Set pointSet = new HashSet<>(); pointSet.add(first); diff --git a/solutions/code/tutorialquestions/question7206/Book.java b/solutions/code/tutorialquestions/question7206/Book.java index 1fb94d8..d578bbf 100755 --- a/solutions/code/tutorialquestions/question7206/Book.java +++ b/solutions/code/tutorialquestions/question7206/Book.java @@ -2,7 +2,7 @@ public class Book { - private int isbn; + private final int isbn; private String title; Book(int isbn, String title) { diff --git a/solutions/code/tutorialquestions/question7206/PrintBook.java b/solutions/code/tutorialquestions/question7206/PrintBook.java index 4deaeab..0e1ee3e 100755 --- a/solutions/code/tutorialquestions/question7206/PrintBook.java +++ b/solutions/code/tutorialquestions/question7206/PrintBook.java @@ -7,7 +7,7 @@ public class PrintBook { public static void main(String[] args) { - Set set = new HashSet(); + Set set = new HashSet<>(); Book book = new Book(1, "C++"); diff --git a/solutions/code/tutorialquestions/question735a/GenericStackArray.java b/solutions/code/tutorialquestions/question735a/GenericStackArray.java index abc9c68..d6e8038 100755 --- a/solutions/code/tutorialquestions/question735a/GenericStackArray.java +++ b/solutions/code/tutorialquestions/question735a/GenericStackArray.java @@ -5,7 +5,7 @@ public class GenericStackArray implements GenericStack { private static final int STACK_LIMIT = 100; - private E[] elements; + private final E[] elements; private int stackPointer; @SuppressWarnings("unchecked") diff --git a/solutions/code/tutorialquestions/question735a/GenericStackList.java b/solutions/code/tutorialquestions/question735a/GenericStackList.java index 9c67f39..5341dbe 100755 --- a/solutions/code/tutorialquestions/question735a/GenericStackList.java +++ b/solutions/code/tutorialquestions/question735a/GenericStackList.java @@ -6,10 +6,10 @@ public class GenericStackList implements GenericStack { - private List elements; + private final List elements; public GenericStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } public void push(E item) { @@ -34,7 +34,7 @@ public GenericIterator iterator() { private class GenericStackListIterator implements GenericIterator { - private ListIterator iterator; + private final ListIterator iterator; private GenericStackListIterator() { iterator = elements.listIterator(elements.size()); diff --git a/solutions/code/tutorialquestions/question735a/MemoryEfficientGenericSet.java b/solutions/code/tutorialquestions/question735a/MemoryEfficientGenericSet.java index 8310916..3cec648 100755 --- a/solutions/code/tutorialquestions/question735a/MemoryEfficientGenericSet.java +++ b/solutions/code/tutorialquestions/question735a/MemoryEfficientGenericSet.java @@ -6,10 +6,10 @@ public class MemoryEfficientGenericSet implements GenericSet { - private List elements; + private final List elements; public MemoryEfficientGenericSet() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override @@ -42,7 +42,7 @@ public GenericIterator iterator() { private class MemoryEfficientGenericSetIterator implements GenericIterator { - private Iterator iterator; + private final Iterator iterator; private MemoryEfficientGenericSetIterator() { iterator = elements.iterator(); diff --git a/solutions/code/tutorialquestions/question735a/SpeedEfficientGenericSet.java b/solutions/code/tutorialquestions/question735a/SpeedEfficientGenericSet.java index 2617808..182dc90 100755 --- a/solutions/code/tutorialquestions/question735a/SpeedEfficientGenericSet.java +++ b/solutions/code/tutorialquestions/question735a/SpeedEfficientGenericSet.java @@ -6,10 +6,10 @@ public class SpeedEfficientGenericSet implements GenericSet { - private Set elements; + private final Set elements; public SpeedEfficientGenericSet() { - elements = new HashSet(); + elements = new HashSet<>(); } @Override @@ -39,7 +39,7 @@ public GenericIterator iterator() { private class MemoryEfficientGenericSetIterator implements GenericIterator { - private Iterator iterator; + private final Iterator iterator; private MemoryEfficientGenericSetIterator() { iterator = elements.iterator(); diff --git a/solutions/code/tutorialquestions/question7ec8/Fighter.java b/solutions/code/tutorialquestions/question7ec8/Fighter.java index 47fd52f..a8af567 100755 --- a/solutions/code/tutorialquestions/question7ec8/Fighter.java +++ b/solutions/code/tutorialquestions/question7ec8/Fighter.java @@ -2,15 +2,15 @@ public class Fighter { - private String name; + private final String name; - private String type; + private final String type; - private int skill; + private final int skill; private int stamina; - private GameEngine theGameEngine; + private final GameEngine theGameEngine; private static final int DAMAGE_VALUE = 2; diff --git a/solutions/code/tutorialquestions/question7ec8/GameEngine.java b/solutions/code/tutorialquestions/question7ec8/GameEngine.java index 63d58e0..b1e5c08 100755 --- a/solutions/code/tutorialquestions/question7ec8/GameEngine.java +++ b/solutions/code/tutorialquestions/question7ec8/GameEngine.java @@ -4,7 +4,7 @@ public class GameEngine { - private Random generator; + private final Random generator; public GameEngine() { generator = new Random(); diff --git a/solutions/code/tutorialquestions/question845d/Book.java b/solutions/code/tutorialquestions/question845d/Book.java index 32fcc81..8ab3772 100755 --- a/solutions/code/tutorialquestions/question845d/Book.java +++ b/solutions/code/tutorialquestions/question845d/Book.java @@ -2,7 +2,7 @@ public class Book { - private String isbn; + private final String isbn; private String title = ""; private int pages = 0; diff --git a/solutions/code/tutorialquestions/question845d/Bookshelf.java b/solutions/code/tutorialquestions/question845d/Bookshelf.java index 26d6cc2..4d9335d 100755 --- a/solutions/code/tutorialquestions/question845d/Bookshelf.java +++ b/solutions/code/tutorialquestions/question845d/Bookshelf.java @@ -6,10 +6,10 @@ public class Bookshelf { - private List contents; + private final List contents; public Bookshelf() { - contents = new LinkedList(); + contents = new LinkedList<>(); } public int size() { diff --git a/solutions/code/tutorialquestions/question845d/Dictionary.java b/solutions/code/tutorialquestions/question845d/Dictionary.java index c21b5ed..ac5efe6 100755 --- a/solutions/code/tutorialquestions/question845d/Dictionary.java +++ b/solutions/code/tutorialquestions/question845d/Dictionary.java @@ -2,8 +2,8 @@ public class Dictionary extends Book { - private String sourceLanguage; - private String targetLanguage; + private final String sourceLanguage; + private final String targetLanguage; private int numDefinitions = 0; public Dictionary(String isbn, String title, int pages, diff --git a/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/AbstractStringStack.java b/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/AbstractStringStack.java index 61d33a6..f12d283 100755 --- a/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/AbstractStringStack.java +++ b/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/AbstractStringStack.java @@ -4,15 +4,15 @@ public abstract class AbstractStringStack implements StringStack { @Override public String toString() { - String result = "["; + final StringBuilder result = new StringBuilder("["); for (StringStackIterator it = iterator(); it.hasNext(); ) { - result += it.next(); + result.append(it.next()); if (it.hasNext()) { - result += ", "; + result.append(", "); } } - result += "]"; - return result; + result.append("]"); + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackArray.java b/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackArray.java index 57eb047..530b2ca 100755 --- a/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackArray.java +++ b/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackArray.java @@ -4,7 +4,7 @@ public class StringStackArray extends AbstractStringStack { private static final int STACK_LIMIT = 100; - private String[] elements; + private final String[] elements; private int stackPointer; public StringStackArray() { diff --git a/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackList.java b/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackList.java index 0dd3ac2..6619cc0 100755 --- a/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackList.java +++ b/solutions/code/tutorialquestions/question85bb/anonymousinnerclasses/StringStackList.java @@ -6,10 +6,10 @@ public class StringStackList extends AbstractStringStack { - private List elements; + private final List elements; public StringStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override @@ -35,7 +35,7 @@ public StringStackIterator iterator() { return new StringStackIterator() { - private ListIterator iterator = elements.listIterator(elements.size()); + private final ListIterator iterator = elements.listIterator(elements.size()); @Override public boolean hasNext() { diff --git a/solutions/code/tutorialquestions/question85bb/innerclasses/AbstractStringStack.java b/solutions/code/tutorialquestions/question85bb/innerclasses/AbstractStringStack.java index e83e9d2..af50000 100755 --- a/solutions/code/tutorialquestions/question85bb/innerclasses/AbstractStringStack.java +++ b/solutions/code/tutorialquestions/question85bb/innerclasses/AbstractStringStack.java @@ -4,15 +4,15 @@ public abstract class AbstractStringStack implements StringStack { @Override public String toString() { - String result = "["; + final StringBuilder result = new StringBuilder("["); for (StringStackIterator it = iterator(); it.hasNext(); ) { - result += it.next(); + result.append(it.next()); if (it.hasNext()) { - result += ", "; + result.append(", "); } } - result += "]"; - return result; + result.append("]"); + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackArray.java b/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackArray.java index 077a4b9..5a19b72 100755 --- a/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackArray.java +++ b/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackArray.java @@ -4,7 +4,7 @@ public class StringStackArray extends AbstractStringStack { private static final int STACK_LIMIT = 100; - private String[] elements; + private final String[] elements; private int stackPointer; public StringStackArray() { diff --git a/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackList.java b/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackList.java index 838b051..b6193c7 100755 --- a/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackList.java +++ b/solutions/code/tutorialquestions/question85bb/innerclasses/StringStackList.java @@ -6,10 +6,10 @@ public class StringStackList extends AbstractStringStack { - private List elements; + private final List elements; public StringStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } public void push(String string) { @@ -36,7 +36,7 @@ public StringStackIterator iterator() { private class StringStackListIterator implements StringStackIterator { - private ListIterator iterator; + private final ListIterator iterator; private StringStackListIterator() { iterator = elements.listIterator(elements.size()); diff --git a/solutions/code/tutorialquestions/question85bb/noinnerclasses/AbstractStringStack.java b/solutions/code/tutorialquestions/question85bb/noinnerclasses/AbstractStringStack.java index e23aeff..2de2775 100755 --- a/solutions/code/tutorialquestions/question85bb/noinnerclasses/AbstractStringStack.java +++ b/solutions/code/tutorialquestions/question85bb/noinnerclasses/AbstractStringStack.java @@ -4,15 +4,15 @@ public abstract class AbstractStringStack implements StringStack { @Override public String toString() { - String result = "["; + final StringBuilder result = new StringBuilder("["); for (StringStackIterator it = iterator(); it.hasNext(); ) { - result += it.next(); + result.append(it.next()); if (it.hasNext()) { - result += ", "; + result.append(", "); } } - result += "]"; - return result; + result.append("]"); + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArray.java b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArray.java index 9cbe091..e015a95 100755 --- a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArray.java +++ b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArray.java @@ -4,7 +4,7 @@ public class StringStackArray extends AbstractStringStack { private static final int STACK_LIMIT = 100; - private String[] elements; + private final String[] elements; private int stackPointer; public StringStackArray() { diff --git a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArrayIterator.java b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArrayIterator.java index cc2f5ea..23cd7c7 100755 --- a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArrayIterator.java +++ b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackArrayIterator.java @@ -5,7 +5,7 @@ class StringStackArrayIterator implements StringStackIterator { private int current; - private String[] elements; + private final String[] elements; StringStackArrayIterator(String[] elements, int stackPointer) { this.elements = elements; diff --git a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackList.java b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackList.java index e22a82f..485caab 100755 --- a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackList.java +++ b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackList.java @@ -5,10 +5,10 @@ public class StringStackList extends AbstractStringStack { - private List elements; + private final List elements; public StringStackList() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override diff --git a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackListIterator.java b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackListIterator.java index ce97994..be0b578 100755 --- a/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackListIterator.java +++ b/solutions/code/tutorialquestions/question85bb/noinnerclasses/StringStackListIterator.java @@ -4,7 +4,7 @@ class StringStackListIterator implements StringStackIterator { - private ListIterator iterator; + private final ListIterator iterator; StringStackListIterator(ListIterator iterator) { this.iterator = iterator; diff --git a/solutions/code/tutorialquestions/question876b/broken/Demo.java b/solutions/code/tutorialquestions/question876b/broken/Demo.java index dc2a979..e503201 100755 --- a/solutions/code/tutorialquestions/question876b/broken/Demo.java +++ b/solutions/code/tutorialquestions/question876b/broken/Demo.java @@ -12,7 +12,7 @@ public static void main(String[] args) { // it doesn't matter for this simple demo, and I don't want its presence // to make me miss other warnings! @SuppressWarnings("unused") - Set setOfB = new HashSet(); + Set setOfB = new HashSet<>(); // Uncommenting the following line causes compiler error // Set setOfA = setOfB; diff --git a/solutions/code/tutorialquestions/question876b/fixed/Demo.java b/solutions/code/tutorialquestions/question876b/fixed/Demo.java index f86432b..51e6c28 100755 --- a/solutions/code/tutorialquestions/question876b/fixed/Demo.java +++ b/solutions/code/tutorialquestions/question876b/fixed/Demo.java @@ -9,11 +9,13 @@ public class Demo { public static void main(String[] args) { - Set setOfB = new HashSet(); - - // Such warnings are generally important - I am suppressing it because - // it doesn't matter for this simple demo, and I don't want its presence + // Such warnings are generally important - I am suppressing them because + // they do not matter for this simple demo, and I don't want their presence // to make me miss other warnings! + + @SuppressWarnings("UnnecessaryLocalVariable") + Set setOfB = new HashSet<>(); + @SuppressWarnings("unused") Set setOfA = setOfB; diff --git a/solutions/code/tutorialquestions/question888a/Example.java b/solutions/code/tutorialquestions/question888a/Example.java new file mode 100755 index 0000000..c4afc0c --- /dev/null +++ b/solutions/code/tutorialquestions/question888a/Example.java @@ -0,0 +1,75 @@ +package tutorialquestions.question888a; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class Example { + + static List concatenate(List> lists) { + return lists + .stream() + .reduce(Collections.emptyList(), + (first, second) -> { + List result = new ArrayList<>(first); + result.addAll(second); + return result; + }); + } + + static List, Optional>> zip(List first, List second) { + return IntStream + .range(0, Math.max(first.size(), second.size())) + .mapToObj(item -> new ImmutablePair, Optional>( + item < first.size() ? Optional.of(first.get(item)) : Optional.empty(), + item < second.size() ? Optional.of(second.get(item)) : Optional.empty())) + .collect(Collectors.toList()); + } + + static List> flatten(List, + Optional>> maybePairs, S defaultS, T defaultT) { + return maybePairs + .stream() + .map(item -> new ImmutablePair<>(item.getFirst() + .orElse(defaultS), item.getSecond().orElse(defaultT))) + .collect(Collectors.toList()); + + } + + public static void main(String[] args) { + + final List strings1 = List.of("Then", "again", "he", "said"); + final List strings2 = List.of("it", "makes", "me", "wonder", "about", "you"); + final List strings3 = List.of("The", "binders", "what", "is", "it", "like"); + final List strings4 = List.of("to", "steal", "a", "soul?"); + + final List floats1 = List.of(1.0f, 2.0f, 3.0f, 4.0f, 5.0f); + final List floats2 = List.of(20.0f, 19.0f, 18.0f, 17.0f, 16.0f, 15.0f); + final List floats3 = Collections.singletonList(10.0f); + final List floats4 = List.of(11.0f, 1.0f); + + final List> listOfListsOfStrings = List.of(strings1, strings2, strings3, + strings4); + final List> listOfListsOfFloats = List.of(floats1, floats2, floats3, + floats4); + System.out.println("Concatenated string lists: " + listOfListsOfStrings); + System.out.println("Concatenated float lists: " + listOfListsOfFloats); + + final List, Optional>> zippedStringLists + = zip(strings1, strings2); + final List, Optional>> zippedStringAndFloatLists + = zip(strings1, floats4); + System.out.println("Zipped string lists: " + zippedStringLists); + System.out.println("Zipped string and float lists: " + zippedStringAndFloatLists); + + final List> flattenedZippedStringAndFloatLists + = flatten(zippedStringAndFloatLists, "NOTHING", -1.0f); + System.out.println("Zipped string an float lists after flattening: " + + flattenedZippedStringAndFloatLists); + } + + +} diff --git a/solutions/code/tutorialquestions/question888a/ImmutablePair.java b/solutions/code/tutorialquestions/question888a/ImmutablePair.java new file mode 100755 index 0000000..9cdb78d --- /dev/null +++ b/solutions/code/tutorialquestions/question888a/ImmutablePair.java @@ -0,0 +1,25 @@ +package tutorialquestions.question888a; + +public class ImmutablePair { + + private final S first; + private final T second; + + public ImmutablePair(S first, T second) { + this.first = first; + this.second = second; + } + + public S getFirst() { + return first; + } + + public T getSecond() { + return second; + } + + @Override + public String toString() { + return "(" + first.toString() + ", " + second.toString() + ")"; + } +} diff --git a/solutions/code/tutorialquestions/question8a61/Demo.java b/solutions/code/tutorialquestions/question8a61/Demo.java index 58988dc..0f8fa5d 100755 --- a/solutions/code/tutorialquestions/question8a61/Demo.java +++ b/solutions/code/tutorialquestions/question8a61/Demo.java @@ -18,7 +18,7 @@ public static IntSet readIntegers(int numIntegers) throws IOException { for (int i = 0; i < numIntegers; i++) { System.out.println("Please enter an int:"); - result.add(new Integer(br.readLine())); + result.add(Integer.parseInt(br.readLine())); } return result; @@ -26,7 +26,7 @@ public static IntSet readIntegers(int numIntegers) throws IOException { public static void main(String[] args) throws IOException { - IntSet integers = readIntegers(new Integer(args[0])); + IntSet integers = readIntegers(Integer.parseInt(args[0])); System.out.println("Set is: " + integers.getClass()); @@ -39,8 +39,8 @@ public static void main(String[] args) throws IOException { System.out.println("Goodbye!"); break; } - System.out.println("Set contains " + new Integer(line) + ": " - + integers.contains(new Integer(line))); + System.out.println("Set contains " + Integer.valueOf(line) + ": " + + integers.contains(Integer.parseInt(line))); } diff --git a/solutions/code/tutorialquestions/question8a61/MemoryEfficientIntSet.java b/solutions/code/tutorialquestions/question8a61/MemoryEfficientIntSet.java index 38d71ae..a277eeb 100755 --- a/solutions/code/tutorialquestions/question8a61/MemoryEfficientIntSet.java +++ b/solutions/code/tutorialquestions/question8a61/MemoryEfficientIntSet.java @@ -5,10 +5,10 @@ public class MemoryEfficientIntSet implements IntSet { - private List elements; + private final List elements; public MemoryEfficientIntSet() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override @@ -34,7 +34,7 @@ public boolean remove(int item) { // Note that // elements.remove(item); // would mean something different! - return elements.remove(new Integer(item)); + return elements.remove(Integer.valueOf(item)); } } diff --git a/solutions/code/tutorialquestions/question8a61/SpeedEfficientIntSet.java b/solutions/code/tutorialquestions/question8a61/SpeedEfficientIntSet.java index b4e7239..1beac1a 100755 --- a/solutions/code/tutorialquestions/question8a61/SpeedEfficientIntSet.java +++ b/solutions/code/tutorialquestions/question8a61/SpeedEfficientIntSet.java @@ -5,10 +5,10 @@ public class SpeedEfficientIntSet implements IntSet { - private Set elements; + private final Set elements; public SpeedEfficientIntSet() { - elements = new HashSet(); + elements = new HashSet<>(); } @Override diff --git a/solutions/code/tutorialquestions/question8d24/GameEngine.java b/solutions/code/tutorialquestions/question8d24/GameEngine.java index 5f188f8..1f16cf5 100755 --- a/solutions/code/tutorialquestions/question8d24/GameEngine.java +++ b/solutions/code/tutorialquestions/question8d24/GameEngine.java @@ -4,7 +4,7 @@ public class GameEngine { - private Random generator; + private final Random generator; public GameEngine() { generator = new Random(); diff --git a/solutions/code/tutorialquestions/question8d24/LuckyFighter.java b/solutions/code/tutorialquestions/question8d24/LuckyFighter.java index 106383e..b369475 100755 --- a/solutions/code/tutorialquestions/question8d24/LuckyFighter.java +++ b/solutions/code/tutorialquestions/question8d24/LuckyFighter.java @@ -2,11 +2,11 @@ public class LuckyFighter { - private String name; + private final String name; - private String type; + private final String type; - private int skill; + private final int skill; private int stamina; @@ -14,9 +14,9 @@ public class LuckyFighter { private int luck; - private Strategy strategy; + private final Strategy strategy; - private GameEngine theGameEngine; + private final GameEngine theGameEngine; /** * Create a LuckyFighter, given a name, type, attributes, and references to a strategy and game diff --git a/solutions/code/tutorialquestions/question8f65/Fighter.java b/solutions/code/tutorialquestions/question8f65/Fighter.java index 6b884c5..1243bd0 100755 --- a/solutions/code/tutorialquestions/question8f65/Fighter.java +++ b/solutions/code/tutorialquestions/question8f65/Fighter.java @@ -2,15 +2,15 @@ public class Fighter { - protected String name; + protected final String name; - protected String type; + protected final String type; - protected int skill; + protected final int skill; protected int stamina; - private GameEngine theGameEngine; + private final GameEngine theGameEngine; private static final int DAMAGE_VALUE = 2; diff --git a/solutions/code/tutorialquestions/question8f65/GameEngine.java b/solutions/code/tutorialquestions/question8f65/GameEngine.java index 943a869..685ac60 100755 --- a/solutions/code/tutorialquestions/question8f65/GameEngine.java +++ b/solutions/code/tutorialquestions/question8f65/GameEngine.java @@ -4,7 +4,7 @@ public class GameEngine { - private Random generator; + private final Random generator; public GameEngine() { generator = new Random(); diff --git a/solutions/code/tutorialquestions/question8f65/LuckyFighter.java b/solutions/code/tutorialquestions/question8f65/LuckyFighter.java index 98e84b9..ad69af3 100755 --- a/solutions/code/tutorialquestions/question8f65/LuckyFighter.java +++ b/solutions/code/tutorialquestions/question8f65/LuckyFighter.java @@ -2,13 +2,13 @@ public class LuckyFighter extends Fighter { - private int initialStamina; + private final int initialStamina; private int luck; - private Strategy strategy; + private final Strategy strategy; - private GameEngine theGameEngine; + private final GameEngine theGameEngine; private static final int AGGRESSIVE_RESISTANCE_THRESHOLD = 2; private static final int AGGRESSIVE_MULTIPLIER = 2; diff --git a/solutions/code/tutorialquestions/question96df/original/TreeNode.java b/solutions/code/tutorialquestions/question96df/original/TreeNode.java index f26e7fe..b56a2c2 100755 --- a/solutions/code/tutorialquestions/question96df/original/TreeNode.java +++ b/solutions/code/tutorialquestions/question96df/original/TreeNode.java @@ -3,7 +3,7 @@ public class TreeNode { private E key; - private TreeNode[] children; + private final TreeNode[] children; @SuppressWarnings("unchecked") public TreeNode(int numberOfChildren) { diff --git a/solutions/code/tutorialquestions/question96df/solution/AbstractTreeNode.java b/solutions/code/tutorialquestions/question96df/solution/AbstractTreeNode.java index d7d447e..0e3e3f6 100755 --- a/solutions/code/tutorialquestions/question96df/solution/AbstractTreeNode.java +++ b/solutions/code/tutorialquestions/question96df/solution/AbstractTreeNode.java @@ -16,18 +16,18 @@ public final void setKey(E key) { @Override public final String toString() { - String result = key.toString(); + final StringBuilder result = new StringBuilder(key.toString()); if (getNumberOfChildren() > 0) { - result += "("; + result.append("("); for (int i = 0; i < getNumberOfChildren(); i++) { - result += getChild(i); + result.append(getChild(i)); if (i < getNumberOfChildren() - 1) { - result += ", "; + result.append(", "); } } - result += ")"; + result.append(")"); } - return result; + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/question96df/solution/Demo.java b/solutions/code/tutorialquestions/question96df/solution/Demo.java index 8c39852..6e3b360 100755 --- a/solutions/code/tutorialquestions/question96df/solution/Demo.java +++ b/solutions/code/tutorialquestions/question96df/solution/Demo.java @@ -4,17 +4,17 @@ public class Demo { public static void main(String[] args) { - final TreeNode root = new GeneralTreeNode(4); - final TreeNode child0 = new BinaryTreeNode(); - final TreeNode child1 = new BinaryTreeNode(); - final TreeNode child2 = new LeafTreeNode(); - final TreeNode child3 = new LeafTreeNode(); - final TreeNode child00 = new LeafTreeNode(); - final TreeNode child01 = new LeafTreeNode(); - final TreeNode child10 = new LeafTreeNode(); - final TreeNode child11 = new BinaryTreeNode(); - final TreeNode child110 = new LeafTreeNode(); - final TreeNode child111 = new LeafTreeNode(); + final TreeNode root = new GeneralTreeNode<>(4); + final TreeNode child0 = new BinaryTreeNode<>(); + final TreeNode child1 = new BinaryTreeNode<>(); + final TreeNode child2 = new LeafTreeNode<>(); + final TreeNode child3 = new LeafTreeNode<>(); + final TreeNode child00 = new LeafTreeNode<>(); + final TreeNode child01 = new LeafTreeNode<>(); + final TreeNode child10 = new LeafTreeNode<>(); + final TreeNode child11 = new BinaryTreeNode<>(); + final TreeNode child110 = new LeafTreeNode<>(); + final TreeNode child111 = new LeafTreeNode<>(); root.setKey("Animal"); child0.setKey("Reptile"); diff --git a/solutions/code/tutorialquestions/question96df/solution/GeneralTreeNode.java b/solutions/code/tutorialquestions/question96df/solution/GeneralTreeNode.java index 12fed1b..e2d0d43 100755 --- a/solutions/code/tutorialquestions/question96df/solution/GeneralTreeNode.java +++ b/solutions/code/tutorialquestions/question96df/solution/GeneralTreeNode.java @@ -2,7 +2,7 @@ public class GeneralTreeNode extends AbstractTreeNode { - private TreeNode[] children; + private final TreeNode[] children; @SuppressWarnings("unchecked") public GeneralTreeNode(int numberOfChildren) { diff --git a/solutions/code/tutorialquestions/question9a9b/AbstractTune.java b/solutions/code/tutorialquestions/question9a9b/AbstractTune.java index 38b08f8..bf1af96 100755 --- a/solutions/code/tutorialquestions/question9a9b/AbstractTune.java +++ b/solutions/code/tutorialquestions/question9a9b/AbstractTune.java @@ -9,17 +9,17 @@ public final Tune transpose(int interval) { @Override public String toString() { - String result = ""; + final StringBuilder result = new StringBuilder(); boolean first = true; for (TuneElement t : this) { if (first) { first = false; } else { - result += " "; + result.append(" "); } - result += t; + result.append(t); } - return result; + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/question9a9b/NoteName.java b/solutions/code/tutorialquestions/question9a9b/NoteName.java index cc13a60..e904d31 100755 --- a/solutions/code/tutorialquestions/question9a9b/NoteName.java +++ b/solutions/code/tutorialquestions/question9a9b/NoteName.java @@ -6,33 +6,20 @@ public enum NoteName { @Override public String toString() { - switch (this) { - case C: - return "C"; - case C_SHARP: - return "C#"; - case D: - return "D"; - case D_SHARP: - return "D#"; - case E: - return "E"; - case F: - return "F"; - case F_SHARP: - return "F#"; - case G: - return "G"; - case G_SHARP: - return "G#"; - case A: - return "A"; - case A_SHARP: - return "A#"; - default: - assert this == B; - return "B"; - } + return switch (this) { + case C -> "C"; + case C_SHARP -> "C#"; + case D -> "D"; + case D_SHARP -> "D#"; + case E -> "E"; + case F -> "F"; + case F_SHARP -> "F#"; + case G -> "G"; + case G_SHARP -> "G#"; + case A -> "A"; + case A_SHARP -> "A#"; + case B -> "B"; + }; } } diff --git a/solutions/code/tutorialquestions/question9a9b/NoteValue.java b/solutions/code/tutorialquestions/question9a9b/NoteValue.java index fb710c5..1070c69 100755 --- a/solutions/code/tutorialquestions/question9a9b/NoteValue.java +++ b/solutions/code/tutorialquestions/question9a9b/NoteValue.java @@ -6,19 +6,13 @@ public enum NoteValue { @Override public String toString() { - switch (this) { - case WHOLE: - return "1"; - case HALF: - return "1/2"; - case QUARTER: - return "1/4"; - case EIGHTH: - return "1/8"; - default: - assert this == SIXTEENTH; - return "1/16"; - } + return switch (this) { + case WHOLE -> "1"; + case HALF -> "1/2"; + case QUARTER -> "1/4"; + case EIGHTH -> "1/8"; + case SIXTEENTH -> "1/16"; + }; } } diff --git a/solutions/code/tutorialquestions/question9a9b/PhysicalTune.java b/solutions/code/tutorialquestions/question9a9b/PhysicalTune.java index ed20333..a3bf085 100755 --- a/solutions/code/tutorialquestions/question9a9b/PhysicalTune.java +++ b/solutions/code/tutorialquestions/question9a9b/PhysicalTune.java @@ -6,10 +6,10 @@ public class PhysicalTune extends AbstractTune { - private List tuneElements; + private final List tuneElements; public PhysicalTune() { - tuneElements = new ArrayList(); + tuneElements = new ArrayList<>(); } @Override diff --git a/solutions/code/tutorialquestions/question9a9b/TransposedTune.java b/solutions/code/tutorialquestions/question9a9b/TransposedTune.java index d118595..710f3f8 100755 --- a/solutions/code/tutorialquestions/question9a9b/TransposedTune.java +++ b/solutions/code/tutorialquestions/question9a9b/TransposedTune.java @@ -4,8 +4,8 @@ public class TransposedTune extends AbstractTune { - private Tune originalTune; - private int interval; + private final Tune originalTune; + private final int interval; TransposedTune(Tune originalTune, int interval) { this.originalTune = originalTune; @@ -50,7 +50,7 @@ private static Note noteFromAbsolutePitch(int pitch, NoteValue value) { private class TransposedTuneIterator implements Iterator { - private Iterator originalTuneIterator; + private final Iterator originalTuneIterator; private TransposedTuneIterator() { originalTuneIterator = originalTune.iterator(); diff --git a/solutions/code/tutorialquestions/questiona22c/checkforcycles/EmailAddress.java b/solutions/code/tutorialquestions/questiona22c/checkforcycles/EmailAddress.java index 62ec232..0274af2 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforcycles/EmailAddress.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforcycles/EmailAddress.java @@ -5,9 +5,9 @@ public abstract class EmailAddress { - private String identifier; + private final String identifier; - private static Set pastIdentifiers = new HashSet(); + private static final Set pastIdentifiers = new HashSet<>(); public EmailAddress(String identifier) throws DuplicateEmailAddressException { if (pastIdentifiers.contains(identifier)) { diff --git a/solutions/code/tutorialquestions/questiona22c/checkforcycles/GroupEmailAddress.java b/solutions/code/tutorialquestions/questiona22c/checkforcycles/GroupEmailAddress.java index 96c2a68..5302b96 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforcycles/GroupEmailAddress.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforcycles/GroupEmailAddress.java @@ -5,11 +5,11 @@ public class GroupEmailAddress extends EmailAddress { - private Set members; + private final Set members; public GroupEmailAddress(String identifier) throws DuplicateEmailAddressException { super(identifier); - members = new HashSet(); + members = new HashSet<>(); } public void addEmailAddress(EmailAddress emailAddress) { @@ -24,7 +24,7 @@ public void addEmailAddress(EmailAddress emailAddress) { @Override public Set getTargets() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (EmailAddress e : members) { result.addAll(e.getTargets()); diff --git a/solutions/code/tutorialquestions/questiona22c/checkforcycles/IndividualEmailAddress.java b/solutions/code/tutorialquestions/questiona22c/checkforcycles/IndividualEmailAddress.java index 12d3dad..7e6d46a 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforcycles/IndividualEmailAddress.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforcycles/IndividualEmailAddress.java @@ -11,7 +11,7 @@ public IndividualEmailAddress(String identifier) throws DuplicateEmailAddressExc @Override public Set getTargets() { - Set result = new HashSet(); + Set result = new HashSet<>(); result.add(this); return result; } diff --git a/solutions/code/tutorialquestions/questiona22c/checkforcycles/Mailbox.java b/solutions/code/tutorialquestions/questiona22c/checkforcycles/Mailbox.java index 6451ba7..8ec1040 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforcycles/Mailbox.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforcycles/Mailbox.java @@ -2,7 +2,7 @@ public class Mailbox { - private String mailboxIdentifier; + private final String mailboxIdentifier; public Mailbox(String mailboxIdentifier) { this.mailboxIdentifier = mailboxIdentifier; diff --git a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/EmailAddress.java b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/EmailAddress.java index 2fe79c7..fae2322 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/EmailAddress.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/EmailAddress.java @@ -5,9 +5,9 @@ public abstract class EmailAddress { - private String identifier; + private final String identifier; - private static Set pastIdentifiers = new HashSet(); + private final static Set pastIdentifiers = new HashSet<>(); public EmailAddress(String identifier) throws DuplicateEmailAddressException { if (pastIdentifiers.contains(identifier)) { diff --git a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/GroupEmailAddress.java b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/GroupEmailAddress.java index d03b835..d48145a 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/GroupEmailAddress.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/GroupEmailAddress.java @@ -5,11 +5,11 @@ public class GroupEmailAddress extends EmailAddress { - private Set members; + private final Set members; public GroupEmailAddress(String identifier) throws DuplicateEmailAddressException { super(identifier); - members = new HashSet(); + members = new HashSet<>(); } public void addEmailAddress(EmailAddress emailAddress) { @@ -19,7 +19,7 @@ public void addEmailAddress(EmailAddress emailAddress) { @Override public Set getTargets() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (EmailAddress e : members) { result.addAll(e.getTargets()); diff --git a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/IndividualEmailAddress.java b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/IndividualEmailAddress.java index 75577bd..a5daa85 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/IndividualEmailAddress.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/IndividualEmailAddress.java @@ -11,7 +11,7 @@ public IndividualEmailAddress(String identifier) throws DuplicateEmailAddressExc @Override public Set getTargets() { - Set result = new HashSet(); + Set result = new HashSet<>(); result.add(this); return result; } diff --git a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/Mailbox.java b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/Mailbox.java index 721e886..9b33540 100755 --- a/solutions/code/tutorialquestions/questiona22c/checkforduplicates/Mailbox.java +++ b/solutions/code/tutorialquestions/questiona22c/checkforduplicates/Mailbox.java @@ -2,7 +2,7 @@ public class Mailbox { - private String mailboxIdentifier; + private final String mailboxIdentifier; public Mailbox(String mailboxIdentifier) { this.mailboxIdentifier = mailboxIdentifier; diff --git a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/AbstractIntSet.java b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/AbstractIntSet.java index f1b0653..7ec489f 100755 --- a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/AbstractIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/AbstractIntSet.java @@ -35,16 +35,18 @@ public boolean contains(IntSet other) { @Override public String toString() { - String result = "["; + final StringBuilder result = new StringBuilder(); + result.append("["); for (IntSetIterator it = iterator(); it.hasNext(); ) { - result += it.next(); + result.append(it.next()); if (it.hasNext()) { - result += ", "; + result.append(", "); } } - return result + "]"; + result.append("]"); + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/Demo.java b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/Demo.java index 0d5d582..16f0a04 100755 --- a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/Demo.java +++ b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/Demo.java @@ -18,7 +18,7 @@ public static IntSet readIntegers(int numIntegers) throws IOException { for (int i = 0; i < numIntegers; i++) { System.out.println("Please enter an int:"); - result.add(new Integer(br.readLine())); + result.add(Integer.parseInt(br.readLine())); } return result; @@ -26,8 +26,8 @@ public static IntSet readIntegers(int numIntegers) throws IOException { public static void main(String[] args) throws IOException { - final int firstSize = new Integer(args[0]); - final int secondSize = new Integer(args[1]); + final int firstSize = Integer.parseInt(args[0]); + final int secondSize = Integer.parseInt(args[1]); System.out.println("Reading first set, of size " + firstSize + ":"); diff --git a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/MemoryEfficientIntSet.java b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/MemoryEfficientIntSet.java index a288ec9..71baaee 100755 --- a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/MemoryEfficientIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/MemoryEfficientIntSet.java @@ -6,10 +6,10 @@ public class MemoryEfficientIntSet extends AbstractIntSet { - private List elements; + private final List elements; public MemoryEfficientIntSet() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override @@ -35,7 +35,7 @@ public boolean remove(int item) { // Note that // elements.remove(item); // would mean something different! - return elements.remove(new Integer(item)); + return elements.remove(Integer.valueOf(item)); } @Override @@ -43,7 +43,7 @@ public IntSetIterator iterator() { return new IntSetIterator() { - private Iterator iterator = elements.iterator(); + private final Iterator iterator = elements.iterator(); @Override public boolean hasNext() { diff --git a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/SpeedEfficientIntSet.java b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/SpeedEfficientIntSet.java index 1a4ac46..dfec86f 100755 --- a/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/SpeedEfficientIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/anonymousinnerclasses/SpeedEfficientIntSet.java @@ -6,10 +6,10 @@ public class SpeedEfficientIntSet extends AbstractIntSet { - private Set elements; + private final Set elements; public SpeedEfficientIntSet() { - elements = new HashSet(); + elements = new HashSet<>(); } @Override @@ -37,7 +37,7 @@ public IntSetIterator iterator() { return new IntSetIterator() { - private Iterator iterator = elements.iterator(); + private final Iterator iterator = elements.iterator(); @Override public boolean hasNext() { diff --git a/solutions/code/tutorialquestions/questiona6e7/innerclasses/AbstractIntSet.java b/solutions/code/tutorialquestions/questiona6e7/innerclasses/AbstractIntSet.java index d53c4b9..9f6f109 100755 --- a/solutions/code/tutorialquestions/questiona6e7/innerclasses/AbstractIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/innerclasses/AbstractIntSet.java @@ -35,16 +35,17 @@ public boolean contains(IntSet other) { @Override public String toString() { - String result = "["; + final StringBuilder result = new StringBuilder(); + result.append("["); for (IntSetIterator it = iterator(); it.hasNext(); ) { - result += it.next(); + result.append(it.next()); if (it.hasNext()) { - result += ", "; + result.append(", "); } } - - return result + "]"; + result.append("]"); + return result.toString(); } } diff --git a/solutions/code/tutorialquestions/questiona6e7/innerclasses/Demo.java b/solutions/code/tutorialquestions/questiona6e7/innerclasses/Demo.java index 6247969..39d771a 100755 --- a/solutions/code/tutorialquestions/questiona6e7/innerclasses/Demo.java +++ b/solutions/code/tutorialquestions/questiona6e7/innerclasses/Demo.java @@ -18,7 +18,7 @@ public static IntSet readIntegers(int numIntegers) throws IOException { for (int i = 0; i < numIntegers; i++) { System.out.println("Please enter an int:"); - result.add(new Integer(br.readLine())); + result.add(Integer.parseInt(br.readLine())); } return result; @@ -26,8 +26,8 @@ public static IntSet readIntegers(int numIntegers) throws IOException { public static void main(String[] args) throws IOException { - final int firstSize = new Integer(args[0]); - final int secondSize = new Integer(args[1]); + final int firstSize = Integer.parseInt(args[0]); + final int secondSize = Integer.parseInt(args[1]); System.out.println("Reading first set, of size " + firstSize + ":"); diff --git a/solutions/code/tutorialquestions/questiona6e7/innerclasses/MemoryEfficientIntSet.java b/solutions/code/tutorialquestions/questiona6e7/innerclasses/MemoryEfficientIntSet.java index dd65463..b3ec9d8 100755 --- a/solutions/code/tutorialquestions/questiona6e7/innerclasses/MemoryEfficientIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/innerclasses/MemoryEfficientIntSet.java @@ -6,10 +6,10 @@ public class MemoryEfficientIntSet extends AbstractIntSet { - private List elements; + private final List elements; public MemoryEfficientIntSet() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override @@ -33,9 +33,9 @@ public boolean isEmpty() { @Override public boolean remove(int item) { // Note that - // elements.remove(x); + // elements.remove(item); // would mean something different! - return elements.remove(new Integer(item)); + return elements.remove(Integer.valueOf(item)); } @Override @@ -45,7 +45,7 @@ public IntSetIterator iterator() { private class MemoryEfficientIntSetIterator implements IntSetIterator { - private Iterator iterator; + private final Iterator iterator; private MemoryEfficientIntSetIterator() { iterator = elements.iterator(); diff --git a/solutions/code/tutorialquestions/questiona6e7/innerclasses/SpeedEfficientIntSet.java b/solutions/code/tutorialquestions/questiona6e7/innerclasses/SpeedEfficientIntSet.java index 51b7961..a8f57f3 100755 --- a/solutions/code/tutorialquestions/questiona6e7/innerclasses/SpeedEfficientIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/innerclasses/SpeedEfficientIntSet.java @@ -6,10 +6,10 @@ public class SpeedEfficientIntSet extends AbstractIntSet { - private Set elements; + private final Set elements; public SpeedEfficientIntSet() { - elements = new HashSet(); + elements = new HashSet<>(); } @Override @@ -39,7 +39,7 @@ public IntSetIterator iterator() { private class SpeedEfficientIntSetIterator implements IntSetIterator { - private Iterator iterator; + private final Iterator iterator; private SpeedEfficientIntSetIterator() { iterator = elements.iterator(); diff --git a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/AbstractIntSet.java b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/AbstractIntSet.java index 2aa0ca7..ca075f9 100755 --- a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/AbstractIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/AbstractIntSet.java @@ -35,12 +35,12 @@ public boolean contains(IntSet other) { @Override public String toString() { - String result = "["; + final StringBuilder result = new StringBuilder("["); for (IntSetIterator it = iterator(); it.hasNext(); ) { - result += it.next(); + result.append(it.next()); if (it.hasNext()) { - result += ", "; + result.append(", "); } } diff --git a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/Demo.java b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/Demo.java index df3896e..6507c3b 100755 --- a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/Demo.java +++ b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/Demo.java @@ -18,7 +18,7 @@ public static IntSet readIntegers(int numIntegers) throws IOException { for (int i = 0; i < numIntegers; i++) { System.out.println("Please enter an int:"); - result.add(new Integer(br.readLine())); + result.add(Integer.parseInt(br.readLine())); } return result; @@ -26,8 +26,8 @@ public static IntSet readIntegers(int numIntegers) throws IOException { public static void main(String[] args) throws IOException { - final int firstSize = new Integer(args[0]); - final int secondSize = new Integer(args[1]); + final int firstSize = Integer.parseInt(args[0]); + final int secondSize = Integer.parseInt(args[1]); System.out.println("Reading first set, of size " + firstSize + ":"); diff --git a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSet.java b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSet.java index bb55f86..d7b1131 100755 --- a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSet.java @@ -5,10 +5,10 @@ public class MemoryEfficientIntSet extends AbstractIntSet { - private List elements; + private final List elements; public MemoryEfficientIntSet() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override @@ -32,9 +32,9 @@ public boolean isEmpty() { @Override public boolean remove(int item) { // Note that - // elements.remove(x); + // elements.remove(item); // would mean something different! - return elements.remove(new Integer(item)); + return elements.remove(Integer.valueOf(item)); } @Override diff --git a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSetIterator.java b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSetIterator.java index f26f2fb..9b7569c 100755 --- a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSetIterator.java +++ b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/MemoryEfficientIntSetIterator.java @@ -5,7 +5,7 @@ // Note package level visibility class MemoryEfficientIntSetIterator implements IntSetIterator { - private Iterator iterator; + private final Iterator iterator; MemoryEfficientIntSetIterator(Iterator iterator) { this.iterator = iterator; diff --git a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSet.java b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSet.java index bc4c36b..84eee09 100755 --- a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSet.java +++ b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSet.java @@ -5,10 +5,10 @@ public class SpeedEfficientIntSet extends AbstractIntSet { - private Set elements; + private final Set elements; public SpeedEfficientIntSet() { - elements = new HashSet(); + elements = new HashSet<>(); } @Override diff --git a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSetIterator.java b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSetIterator.java index 6715b4f..18aa864 100755 --- a/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSetIterator.java +++ b/solutions/code/tutorialquestions/questiona6e7/noinnerclasses/SpeedEfficientIntSetIterator.java @@ -5,7 +5,7 @@ // Note package level visibility class SpeedEfficientIntSetIterator implements IntSetIterator { - Iterator iterator; + final Iterator iterator; SpeedEfficientIntSetIterator(Iterator iterator) { this.iterator = iterator; diff --git a/solutions/code/tutorialquestions/questionaa68/ColouredPoint.java b/solutions/code/tutorialquestions/questionaa68/ColouredPoint.java index 8b661a1..d1951a0 100755 --- a/solutions/code/tutorialquestions/questionaa68/ColouredPoint.java +++ b/solutions/code/tutorialquestions/questionaa68/ColouredPoint.java @@ -30,10 +30,8 @@ public boolean equals(Object that) { ColouredPoint thatPoint = (ColouredPoint) that; - if (!thatPoint.canEqual(this)) { - return false; - } - + // Note: thatPoint.canEqual(this) will be checked as part of + // super.equals(thatPoint). return super.equals(thatPoint) && colour == thatPoint.colour; } diff --git a/solutions/code/tutorialquestions/questionb33f/Demo.java b/solutions/code/tutorialquestions/questionb33f/Demo.java new file mode 100755 index 0000000..44b0633 --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/Demo.java @@ -0,0 +1,59 @@ +package tutorialquestions.questionb33f; + +import java.io.IOException; +import java.util.Optional; +import java.util.Set; + +public class Demo { + + private static final int MAX_LINE_SIZE = 100; + + public static void main(String[] args) throws IOException { + + if (args.length != 3) { + System.err.println("Requires three file names: input file, output file 1, output file 2."); + } + + final Logger stderrLogger = (logLevel, message) -> { + switch (logLevel) { + case FATAL, ERROR, WARNING -> System.err.print("*** IMPORTANT ***\n"); + default -> System.err.print("* NOTE *\n"); + } + System.err.println(message); + }; + + final StringInspector lineTooLongInspector = + (item -> item.length() > MAX_LINE_SIZE + ? Optional.of(new ImmutablePair<>( + LogLevel.ERROR, "Line too long: " + item)) + : Optional.empty()); + + final FileInspector inspector1 = new FileInspector( + stderrLogger); + + FileLogger fileLogger1 = new FileLogger(args[1]); + final FileInspector inspector2 = new FileInspector(fileLogger1); + + FileLogger fileLogger2 = new FileLogger(args[2]); + final FileInspector inspector3 = new FileInspector(fileLogger2); + + final KnownWordsStringInspector knownWordsInspector = new KnownWordsStringInspector( + Set.of("goto", "finalize", "static"), + Set.of("continue", "break") + ); + + System.err.println("Starting inspection 1:"); + inspector1.inspectFile(args[0], lineTooLongInspector); + System.err.println("\nStarting inspection 2:"); + inspector1.inspectFile(args[0], knownWordsInspector); + System.err.println("\nStarting inspection 3 (see " + args[1] + " for details)."); + inspector2.inspectFile(args[0], lineTooLongInspector); + System.err.println("\nStarting inspection 4 (see " + args[2] + " for details)."); + inspector3.inspectFile(args[0], knownWordsInspector); + + fileLogger1.close(); + fileLogger2.close(); + + } + +} diff --git a/solutions/code/tutorialquestions/questionb33f/FileInspector.java b/solutions/code/tutorialquestions/questionb33f/FileInspector.java new file mode 100755 index 0000000..a080412 --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/FileInspector.java @@ -0,0 +1,25 @@ +package tutorialquestions.questionb33f; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +public class FileInspector { + + private final Logger logger; + + public FileInspector(Logger logger) { + this.logger = logger; + } + + public void inspectFile(String filename, StringInspector stringInspector) throws IOException { + final BufferedReader br = new BufferedReader(new FileReader(filename)); + String line; + while ((line = br.readLine()) != null) { + // In the case that the line turns out to be interesting, ask the logger to log the message + // reported by the string inspector, at the logging level it advises. + stringInspector.inspect(line) + .ifPresent(item -> logger.log(item.getFirst(), item.getSecond())); + } + } +} diff --git a/solutions/code/tutorialquestions/questionb33f/FileLogger.java b/solutions/code/tutorialquestions/questionb33f/FileLogger.java new file mode 100755 index 0000000..28267f1 --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/FileLogger.java @@ -0,0 +1,32 @@ +package tutorialquestions.questionb33f; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Set; + +public class FileLogger implements Logger { + + private final BufferedWriter writer; + + public FileLogger(String logfileName) throws IOException { + this.writer = new BufferedWriter(new FileWriter(logfileName)); + } + + @Override + public void log(LogLevel logLevel, String message) { + if (Set.of(LogLevel.INFO, LogLevel.VERBOSE).contains(logLevel)) { + return; + } + try { + writer.write(logLevel.toString() + ": " + message + "\n"); + } catch (IOException exception) { + // Ignore the exception. + } + } + + public void close() throws IOException { + writer.close(); + } + +} diff --git a/solutions/code/tutorialquestions/questionb33f/ImmutablePair.java b/solutions/code/tutorialquestions/questionb33f/ImmutablePair.java new file mode 100755 index 0000000..acd4dbe --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/ImmutablePair.java @@ -0,0 +1,21 @@ +package tutorialquestions.questionb33f; + +public class ImmutablePair { + + private final S first; + private final T second; + + public ImmutablePair(S first, T second) { + this.first = first; + this.second = second; + } + + public S getFirst() { + return first; + } + + public T getSecond() { + return second; + } + +} diff --git a/solutions/code/tutorialquestions/questionb33f/KnownWordsStringInspector.java b/solutions/code/tutorialquestions/questionb33f/KnownWordsStringInspector.java new file mode 100755 index 0000000..157f352 --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/KnownWordsStringInspector.java @@ -0,0 +1,51 @@ +package tutorialquestions.questionb33f; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +public class KnownWordsStringInspector implements StringInspector { + + private final Set errorWords; + + private final Set verboseWords; + + public KnownWordsStringInspector(Set errorWords, Set verboseWords) { + this.errorWords = errorWords; + this.verboseWords = verboseWords; + } + + @Override + public Optional> inspect(String input) { + final List observedErrorWords = new ArrayList<>(); + final List observedVerboseWords = new ArrayList<>(); + for (String component : input.split(" ")) { + if (errorWords.contains(component)) { + observedErrorWords.add(component); + } else if (verboseWords.contains(component)) { + observedVerboseWords.add(component); + } + } + if (observedErrorWords.isEmpty() && observedVerboseWords.isEmpty()) { + return Optional.empty(); + } + + final StringBuilder message = new StringBuilder(); + if (!observedErrorWords.isEmpty()) { + message.append("Observed the following error words: "); + message.append(observedErrorWords); + message.append("\n"); + } + if (!observedVerboseWords.isEmpty()) { + message.append("Observed the following words of note: "); + message.append(observedVerboseWords); + message.append("\n"); + } + return Optional.of(new ImmutablePair<>( + !observedErrorWords.isEmpty() ? LogLevel.ERROR : LogLevel.VERBOSE, + message.toString() + )); + } + +} diff --git a/solutions/code/tutorialquestions/questionb33f/LogLevel.java b/solutions/code/tutorialquestions/questionb33f/LogLevel.java new file mode 100755 index 0000000..22426fb --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/LogLevel.java @@ -0,0 +1,5 @@ +package tutorialquestions.questionb33f; + +public enum LogLevel { + VERBOSE, INFO, WARNING, ERROR, FATAL +} diff --git a/solutions/code/tutorialquestions/questionb33f/Logger.java b/solutions/code/tutorialquestions/questionb33f/Logger.java new file mode 100755 index 0000000..9a5b5ed --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/Logger.java @@ -0,0 +1,8 @@ +package tutorialquestions.questionb33f; + +@FunctionalInterface +public interface Logger { + + void log(LogLevel logLevel, String message); + +} diff --git a/solutions/code/tutorialquestions/questionb33f/StringInspector.java b/solutions/code/tutorialquestions/questionb33f/StringInspector.java new file mode 100755 index 0000000..abe3b88 --- /dev/null +++ b/solutions/code/tutorialquestions/questionb33f/StringInspector.java @@ -0,0 +1,18 @@ +package tutorialquestions.questionb33f; + +import java.util.Optional; + +@FunctionalInterface +public interface StringInspector { + + /** + * An implementation of this method should decide whether there is anything interesting to say + * about 'input'. If there is not, it should return 'Optional.empty()'. Otherwise it should + * return a pair indicating, via a LogLevel, the severity of the information to be reported, + * together with the information to be reported. + * @param input A string to be inspected. + * @return Optionally a (severity level, message) pair. + */ + Optional> inspect(String input); + +} diff --git a/solutions/code/tutorialquestions/questionb401/Demo.java b/solutions/code/tutorialquestions/questionb401/Demo.java index 3c0aaf5..8570d69 100755 --- a/solutions/code/tutorialquestions/questionb401/Demo.java +++ b/solutions/code/tutorialquestions/questionb401/Demo.java @@ -9,8 +9,8 @@ public class Demo { public static GenericSet readIntegers(int numIntegers) throws IOException { - GenericSet result = (numIntegers > 10 ? new MemoryEfficientGenericSet() - : new SpeedEfficientGenericSet()); + GenericSet result = (numIntegers > 10 ? new MemoryEfficientGenericSet<>() + : new SpeedEfficientGenericSet<>()); BufferedReader br = new BufferedReader( new InputStreamReader( @@ -20,7 +20,7 @@ public static GenericSet readIntegers(int numIntegers) throws IOExcepti for (int i = 0; i < numIntegers; i++) { System.out.println("Please enter an int:"); - result.add(new Integer(br.readLine())); + result.add(Integer.valueOf(br.readLine())); } return result; @@ -30,7 +30,7 @@ public static void main(String[] args) throws IOException { // Testing the generic set on a couple of types - GenericSet stringSet = new MemoryEfficientGenericSet(); + GenericSet stringSet = new MemoryEfficientGenericSet<>(); stringSet.add("Hello"); @@ -44,7 +44,7 @@ public static void main(String[] args) throws IOException { assert !stringSet.contains("Cat"); - GenericSet printStreamSet = new SpeedEfficientGenericSet(); + GenericSet printStreamSet = new SpeedEfficientGenericSet<>(); printStreamSet.add(System.out); @@ -58,7 +58,7 @@ public static void main(String[] args) throws IOException { // Now doing the "readIntegers" part - GenericSet integers = readIntegers(new Integer(args[0])); + GenericSet integers = readIntegers(Integer.parseInt(args[0])); System.out.println("Set is: " + integers.getClass()); @@ -71,8 +71,8 @@ public static void main(String[] args) throws IOException { System.out.println("Goodbye!"); break; } - System.out.println("Set contains " + new Integer(line) + ": " - + integers.contains(new Integer(line))); + System.out.println("Set contains " + Integer.valueOf(line) + ": " + + integers.contains(Integer.valueOf(line))); } diff --git a/solutions/code/tutorialquestions/questionb401/MemoryEfficientGenericSet.java b/solutions/code/tutorialquestions/questionb401/MemoryEfficientGenericSet.java index 9226caa..7812c96 100755 --- a/solutions/code/tutorialquestions/questionb401/MemoryEfficientGenericSet.java +++ b/solutions/code/tutorialquestions/questionb401/MemoryEfficientGenericSet.java @@ -5,10 +5,10 @@ public class MemoryEfficientGenericSet implements GenericSet { - private List elements; + private final List elements; public MemoryEfficientGenericSet() { - elements = new ArrayList(); + elements = new ArrayList<>(); } @Override diff --git a/solutions/code/tutorialquestions/questionb401/SpeedEfficientGenericSet.java b/solutions/code/tutorialquestions/questionb401/SpeedEfficientGenericSet.java index a5fa331..e94b93a 100755 --- a/solutions/code/tutorialquestions/questionb401/SpeedEfficientGenericSet.java +++ b/solutions/code/tutorialquestions/questionb401/SpeedEfficientGenericSet.java @@ -5,10 +5,10 @@ public class SpeedEfficientGenericSet implements GenericSet { - private Set elements; + private final Set elements; public SpeedEfficientGenericSet() { - elements = new HashSet(); + elements = new HashSet<>(); } @Override diff --git a/solutions/code/tutorialquestions/questionb4a5/A.java b/solutions/code/tutorialquestions/questionb4a5/A.java index 91830b4..de4e6b5 100755 --- a/solutions/code/tutorialquestions/questionb4a5/A.java +++ b/solutions/code/tutorialquestions/questionb4a5/A.java @@ -4,12 +4,15 @@ public class A { static int numCollected = 0; - private int id; + private final int id; public A(int id) { this.id = id; } + // This example is used to explore garbage collector behaviour via 'finalize', so we suppress + // Checkstyle's generally sound advice to avoid using 'finalize' here. + @SuppressWarnings({"checkstyle:nofinalizer", "deprecation"}) @Override public void finalize() { System.out.println("Instance " + id + " collected"); diff --git a/solutions/code/tutorialquestions/questionbec2/Artist.java b/solutions/code/tutorialquestions/questionbec2/Artist.java index cd5b479..ba23d0c 100755 --- a/solutions/code/tutorialquestions/questionbec2/Artist.java +++ b/solutions/code/tutorialquestions/questionbec2/Artist.java @@ -5,18 +5,18 @@ public class Artist { - private String name; + private final String name; - private List cataloue; + private final List catalogue; - private Genre mainGenre; + private final Genre mainGenre; /** * Create an artist given a name and main genre. */ public Artist(String name, Genre mainGenre) { this.name = name; - this.cataloue = new ArrayList(); + this.catalogue = new ArrayList<>(); this.mainGenre = mainGenre; } @@ -28,14 +28,14 @@ public void addRecord(String name) { * Add a record to the catalogue with the given name and genre. */ public void addRecord(String name, Genre genre) { - cataloue.add(new Record(name, genre)); + catalogue.add(new Record(name, genre)); } /** * Show details of the catalogue, to standard output. */ public void showCatalogue() { - for (Record r : cataloue) { + for (Record r : catalogue) { System.out.println(r); } } @@ -44,7 +44,7 @@ public void showCatalogue() { * Show details of all records in the catalogue matching the given genre. */ public void showGenre(Genre genre) { - for (Record r : cataloue) { + for (Record r : catalogue) { if (r.getGenre() == genre) { System.out.println(r); } diff --git a/solutions/code/tutorialquestions/questionbec2/Genre.java b/solutions/code/tutorialquestions/questionbec2/Genre.java index f6be34a..e5cfa7e 100755 --- a/solutions/code/tutorialquestions/questionbec2/Genre.java +++ b/solutions/code/tutorialquestions/questionbec2/Genre.java @@ -5,17 +5,11 @@ public enum Genre { @Override public String toString() { - switch (this) { - case ROCK: - return "Rock"; - case POP: - return "Pop"; - case JAZZ: - return "Jazz"; - default: - assert false : "Unknown genre"; - return null; - } + return switch(this) { + case ROCK -> "Rock"; + case POP -> "Pop"; + case JAZZ -> "Jazz"; + }; } } diff --git a/solutions/code/tutorialquestions/questionbec2/Main.java b/solutions/code/tutorialquestions/questionbec2/Main.java index 7c9ebef..c7717cc 100755 --- a/solutions/code/tutorialquestions/questionbec2/Main.java +++ b/solutions/code/tutorialquestions/questionbec2/Main.java @@ -20,7 +20,7 @@ public static void main(String[] args) { System.out.println("All records by " + queen.getName() + ":"); queen.showCatalogue(); - System.out.println(""); + System.out.println(); System.out.println("All " + Genre.ROCK + " records by " + queen.getName() + ":"); queen.showGenre(Genre.ROCK); diff --git a/solutions/code/tutorialquestions/questionbec2/Record.java b/solutions/code/tutorialquestions/questionbec2/Record.java index da31625..eb8089b 100755 --- a/solutions/code/tutorialquestions/questionbec2/Record.java +++ b/solutions/code/tutorialquestions/questionbec2/Record.java @@ -2,9 +2,9 @@ public class Record { - private String name; + private final String name; - private Genre genre; + private final Genre genre; public Record(String name, Genre genre) { this.name = name; diff --git a/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/DrawingEngine.java b/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/DrawingEngine.java index 7747c2c..bd5203e 100755 --- a/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/DrawingEngine.java +++ b/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/DrawingEngine.java @@ -5,10 +5,10 @@ public class DrawingEngine { - private Set rectangles; + private final Set rectangles; public DrawingEngine() { - rectangles = new HashSet(); + rectangles = new HashSet<>(); } public void addRectangle(Rectangle rectangle) { @@ -28,11 +28,11 @@ public int maxArea() { @Override public String toString() { - String result = "Drawing engine is looking after these rectangles:"; + final StringBuilder result = new StringBuilder("Drawing engine is looking after these rectangles:"); for (Rectangle r : rectangles) { - result += "\n " + r; + result.append("\n ").append(r); } - return result; + return result.toString(); } diff --git a/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/Point.java b/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/Point.java index b34adaf..a5c29e7 100755 --- a/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/Point.java +++ b/solutions/code/tutorialquestions/questionc2b8/afterrefactoring/Point.java @@ -2,8 +2,8 @@ public class Point { - private int coordX; - private int coordY; + private final int coordX; + private final int coordY; public Point(int coordX, int coordY) { this.coordX = coordX; diff --git a/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/DrawingEngine.java b/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/DrawingEngine.java index c058122..177c465 100755 --- a/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/DrawingEngine.java +++ b/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/DrawingEngine.java @@ -5,10 +5,10 @@ public class DrawingEngine { - private Set rectangles; + private final Set rectangles; public DrawingEngine() { - rectangles = new HashSet(); + rectangles = new HashSet<>(); } public void addRectangle(Rectangle rectangle) { @@ -46,11 +46,11 @@ public int maxArea() { public String toString() { - String result = "Drawing engine is looking after these rectangles:"; + final StringBuilder result = new StringBuilder("Drawing engine is looking after these rectangles:"); for (Rectangle r : rectangles) { - result += "\n " + rectangleToString(r); + result.append("\n ").append(rectangleToString(r)); } - return result; + return result.toString(); } diff --git a/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/Point.java b/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/Point.java index 241b8b7..1b36cd9 100755 --- a/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/Point.java +++ b/solutions/code/tutorialquestions/questionc2b8/beforerefactoring/Point.java @@ -2,8 +2,8 @@ public class Point { - private int coordX; - private int coordY; + private final int coordX; + private final int coordY; public Point(int coordX, int coordY) { this.coordX = coordX; diff --git a/solutions/code/tutorialquestions/questionc822/TreeNodeTest1.java b/solutions/code/tutorialquestions/questionc822/TreeNodeTest1.java index 8855e9e..ae1feee 100755 --- a/solutions/code/tutorialquestions/questionc822/TreeNodeTest1.java +++ b/solutions/code/tutorialquestions/questionc822/TreeNodeTest1.java @@ -7,9 +7,9 @@ public class TreeNodeTest1 { public static void main(String[] args) { - TreeNode n1 = new TreeNode(1); + TreeNode n1 = new TreeNode<>(1); n1.setKey("A"); - TreeNode n2 = new TreeNode(1); + TreeNode n2 = new TreeNode<>(1); n2.setKey("B"); n1.setChild(0, n2); n2.setChild(0, n1); diff --git a/solutions/code/tutorialquestions/questionc822/TreeNodeTest2.java b/solutions/code/tutorialquestions/questionc822/TreeNodeTest2.java index 60f02f4..b3cc52b 100755 --- a/solutions/code/tutorialquestions/questionc822/TreeNodeTest2.java +++ b/solutions/code/tutorialquestions/questionc822/TreeNodeTest2.java @@ -6,11 +6,11 @@ public class TreeNodeTest2 { public static void main(String[] args) { - TreeNode n3 = new TreeNode(2); + TreeNode n3 = new TreeNode<>(2); n3.setKey("C"); - TreeNode n4 = new TreeNode(1); + TreeNode n4 = new TreeNode<>(1); n4.setKey("D"); - TreeNode n5 = new TreeNode(0); + TreeNode n5 = new TreeNode<>(0); n5.setKey("E"); n3.setChild(0, n4); n3.setChild(1, n5); diff --git a/solutions/code/tutorialquestions/questionc822/precondition/TreeNode.java b/solutions/code/tutorialquestions/questionc822/precondition/TreeNode.java index af847e6..2ac7c64 100755 --- a/solutions/code/tutorialquestions/questionc822/precondition/TreeNode.java +++ b/solutions/code/tutorialquestions/questionc822/precondition/TreeNode.java @@ -4,7 +4,7 @@ public class TreeNode { private E key; - private TreeNode[] children; + private final TreeNode[] children; private int numberOfParents; @SuppressWarnings("unchecked") @@ -47,7 +47,7 @@ public void setKey(E key) { } public TreeNode clone() { - TreeNode result = new TreeNode(getNumberOfChildren()); + TreeNode result = new TreeNode<>(getNumberOfChildren()); for (int i = 0; i < getNumberOfChildren(); i++) { result.setChild(i, getChild(i).clone()); } diff --git a/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest1.java b/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest1.java index 0bc0a43..e13ae2f 100755 --- a/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest1.java +++ b/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest1.java @@ -5,9 +5,9 @@ public class TreeNodeTest1 { public static void main(String[] args) { - TreeNode n1 = new TreeNode(1); + TreeNode n1 = new TreeNode<>(1); n1.setKey("A"); - TreeNode n2 = new TreeNode(1); + TreeNode n2 = new TreeNode<>(1); n2.setKey("B"); n1.setChild(0, n2); n2.setChild(0, n1); diff --git a/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest2.java b/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest2.java index 49a845a..817e9d3 100755 --- a/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest2.java +++ b/solutions/code/tutorialquestions/questionc822/precondition/TreeNodeTest2.java @@ -7,11 +7,11 @@ public class TreeNodeTest2 { */ public static void main(String[] args) { - TreeNode n3 = new TreeNode(2); + TreeNode n3 = new TreeNode<>(2); n3.setKey("C"); - TreeNode n4 = new TreeNode(1); + TreeNode n4 = new TreeNode<>(1); n4.setKey("D"); - TreeNode n5 = new TreeNode(0); + TreeNode n5 = new TreeNode<>(0); n5.setKey("E"); n3.setChild(0, n4); n3.setChild(1, n5); diff --git a/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Date.java b/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Date.java index 5575594..1171baf 100755 --- a/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Date.java +++ b/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Date.java @@ -2,70 +2,39 @@ public class Date { - private final int dayOfBirth; - private final int monthOfBirth; - private final int yearOfBirth; - - public Date(int dayOfBirth, int monthOfBirth, int yearOfBirth) { - this.dayOfBirth = dayOfBirth; - this.monthOfBirth = monthOfBirth; - this.yearOfBirth = yearOfBirth; + private final int day; + private final int month; + private final int year; + + public Date(int day, int month, int year) { + this.day = day; + this.month = month; + this.year = year; } public boolean isValid() { - if (yearOfBirth < 0) { - return false; - } - - if (monthOfBirth < 1 || yearOfBirth > 12) { + if (year < 0 || day < 1) { return false; } - - if (dayOfBirth < 1) { - return false; - } - - switch (monthOfBirth) { - case 1: - case 3: - case 5: - case 7: - case 8: - case 10: - case 12: - if (dayOfBirth > 31) { - return false; - } - break; - case 4: - case 6: - case 9: - case 11: - if (dayOfBirth > 30) { - return false; - } - // fall through - default: - assert monthOfBirth == 2; - if (dayOfBirth > (isLeapYear() ? 29 : 28)) { - return false; - } - } - - return true; - + + return switch (month) { + case 2 -> day <= (isLeapYear() ? 29 : 28); + case 4, 6, 9, 11 -> day <= 30; + case 1, 3, 5, 7, 8, 10, 12 -> day <= 31; + default -> false; + }; } private boolean isLeapYear() { // Deliberately simplified version of // leap year calculation - return (yearOfBirth % 4 == 0); + return (year % 4 == 0); } @Override public String toString() { - return dayOfBirth + "/" + monthOfBirth + "/" + yearOfBirth; + return day + "/" + month + "/" + year; } } diff --git a/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Name.java b/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Name.java index ed2f34e..0d7244a 100755 --- a/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Name.java +++ b/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Name.java @@ -21,12 +21,12 @@ public String getSurname() { } public String getInitials() { - String result = ""; + final StringBuilder result = new StringBuilder(); StringTokenizer strTok = new StringTokenizer(forenames); while (strTok.hasMoreTokens()) { - result += strTok.nextToken().charAt(0); + result.append(strTok.nextToken().charAt(0)); } - return result + surname.charAt(0); + return result.toString() + surname.charAt(0); } @Override diff --git a/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Person.java b/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Person.java index 0d75844..e7f3379 100755 --- a/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Person.java +++ b/solutions/code/tutorialquestions/questiond363/afterfixingandrefactoring/Person.java @@ -3,13 +3,13 @@ public class Person { - private Name name; + private final Name name; - private Date dateOfBirth; + private final Date dateOfBirth; - private Address address; + private final Address address; - private NiNumber nationalInsuranceNumber; + private final NiNumber nationalInsuranceNumber; public Person(Name name, Date dateOfBirth, Address address, NiNumber nationalInsuranceNumber) { this.name = name; diff --git a/solutions/code/tutorialquestions/questiond363/beforefixingandrefactoring/Person.java b/solutions/code/tutorialquestions/questiond363/beforefixingandrefactoring/Person.java index d25ce34..2ea121c 100755 --- a/solutions/code/tutorialquestions/questiond363/beforefixingandrefactoring/Person.java +++ b/solutions/code/tutorialquestions/questiond363/beforefixingandrefactoring/Person.java @@ -4,19 +4,19 @@ public class Person { - private String forenames; - private String surname; + private final String forenames; + private final String surname; - private int dayOfBirth; - private int monthOfBirth; - private int yearOfBirth; + private final int dayOfBirth; + private final int monthOfBirth; + private final int yearOfBirth; - private int houseNumber; - private String address1; - private String address2; - private String postCode; + private final int houseNumber; + private final String address1; + private final String address2; + private final String postCode; - private String nationalInsuranceNumber; + private final String nationalInsuranceNumber; public Person(String forename, String surname, int dayOfBirth, @@ -93,12 +93,12 @@ public boolean sameAddress(Person other) { } public String getInitials() { - String result = ""; + final StringBuilder result = new StringBuilder(); StringTokenizer strTok = new StringTokenizer(forenames); while (strTok.hasMoreTokens()) { - result += strTok.nextToken().charAt(0); + result.append(strTok.nextToken().charAt(0)); } - return result + surname.charAt(0); + return result.toString() + surname.charAt(0); } private boolean isLeapYear() { diff --git a/solutions/code/tutorialquestions/questiond3f5/Example.java b/solutions/code/tutorialquestions/questiond3f5/Example.java new file mode 100755 index 0000000..5352390 --- /dev/null +++ b/solutions/code/tutorialquestions/questiond3f5/Example.java @@ -0,0 +1,74 @@ +package tutorialquestions.questiond3f5; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Example { + + static Stream restrictToPositiveIntegers(Stream numbers) { + return numbers.filter(item -> item instanceof Integer) + .map(item -> (Integer) item) + .filter(item -> item > 0); + } + + static Stream restrictToPositiveIntegersBoundedWildcard( + Stream numbers) { + return numbers.filter(item -> item instanceof Integer) + .map(item -> (Integer) item) + .filter(item -> item > 0); + } + + public static void main(String[] args) { + + final List numbers = List.of( + 5, + 2, + 3.0f, + -20.0, + (short) -1, + -12, + -200, + 200, + 0); + + final List floats = List.of( + 10.0, + -20.0, + 31.0, + 412.34); + + final List integers = List.of( + 1, + -1, + 2, + -2, + 3, + -3, + 4, + -4, + 0); + + System.out.println("Positive integers from " + numbers + " are: " + + restrictToPositiveIntegers(numbers.stream()).collect(Collectors.toList())); + + // Think about why the following would not compile: + // System.out.println("Positive integers from " + floats + " are: " + // + restrictToPositiveIntegers(floats.stream()).collect(Collectors.toList())); + + // ... and the following: + // System.out.println("Positive integers from " + integers + " are: " + // + restrictToPositiveIntegers(integers.stream()).collect(Collectors.toList())); + + System.out.println("Positive integers from " + floats + " are: " + + restrictToPositiveIntegersBoundedWildcard(floats + .stream()) + .collect(Collectors.toList())); + System.out.println("Positive integers from " + integers + " are: " + + restrictToPositiveIntegersBoundedWildcard(integers + .stream()) + .collect(Collectors.toList())); + + } + +} diff --git a/solutions/code/tutorialquestions/questiondc38/acyclic/EmailAddress.java b/solutions/code/tutorialquestions/questiondc38/acyclic/EmailAddress.java index 82c4dfa..3ea8da7 100755 --- a/solutions/code/tutorialquestions/questiondc38/acyclic/EmailAddress.java +++ b/solutions/code/tutorialquestions/questiondc38/acyclic/EmailAddress.java @@ -4,7 +4,7 @@ public abstract class EmailAddress { - private String identifier; + private final String identifier; public EmailAddress(String identifier) { this.identifier = identifier; diff --git a/solutions/code/tutorialquestions/questiondc38/acyclic/GroupEmailAddress.java b/solutions/code/tutorialquestions/questiondc38/acyclic/GroupEmailAddress.java index eed568c..0853d92 100755 --- a/solutions/code/tutorialquestions/questiondc38/acyclic/GroupEmailAddress.java +++ b/solutions/code/tutorialquestions/questiondc38/acyclic/GroupEmailAddress.java @@ -5,11 +5,11 @@ public class GroupEmailAddress extends EmailAddress { - private Set members; + private final Set members; public GroupEmailAddress(String identifier) { super(identifier); - members = new HashSet(); + members = new HashSet<>(); } public void addEmailAddress(EmailAddress emailAddress) { @@ -19,7 +19,7 @@ public void addEmailAddress(EmailAddress emailAddress) { @Override public Set getTargets() { - Set result = new HashSet(); + Set result = new HashSet<>(); for (EmailAddress e : members) { result.addAll(e.getTargets()); diff --git a/solutions/code/tutorialquestions/questiondc38/acyclic/IndividualEmailAddress.java b/solutions/code/tutorialquestions/questiondc38/acyclic/IndividualEmailAddress.java index 488c039..ac045ba 100755 --- a/solutions/code/tutorialquestions/questiondc38/acyclic/IndividualEmailAddress.java +++ b/solutions/code/tutorialquestions/questiondc38/acyclic/IndividualEmailAddress.java @@ -11,7 +11,7 @@ public IndividualEmailAddress(String identifier) { @Override public Set getTargets() { - Set result = new HashSet(); + Set result = new HashSet<>(); result.add(this); return result; } diff --git a/solutions/code/tutorialquestions/questiondc38/acyclic/Mailbox.java b/solutions/code/tutorialquestions/questiondc38/acyclic/Mailbox.java index e3f7ca8..656c095 100755 --- a/solutions/code/tutorialquestions/questiondc38/acyclic/Mailbox.java +++ b/solutions/code/tutorialquestions/questiondc38/acyclic/Mailbox.java @@ -2,7 +2,7 @@ public class Mailbox { - private String mailboxIdentifier; + private final String mailboxIdentifier; public Mailbox(String mailboxIdentifier) { this.mailboxIdentifier = mailboxIdentifier; diff --git a/solutions/code/tutorialquestions/questiondc38/cyclic/EmailAddress.java b/solutions/code/tutorialquestions/questiondc38/cyclic/EmailAddress.java index 1cabec9..3aba99d 100755 --- a/solutions/code/tutorialquestions/questiondc38/cyclic/EmailAddress.java +++ b/solutions/code/tutorialquestions/questiondc38/cyclic/EmailAddress.java @@ -5,14 +5,14 @@ public abstract class EmailAddress { - private String identifier; + private final String identifier; public EmailAddress(String identifier) { this.identifier = identifier; } public final Set getTargets() { - return getTargets(new HashSet()); + return getTargets(new HashSet<>()); } protected abstract Set getTargets(Set alreadySeen); diff --git a/solutions/code/tutorialquestions/questiondc38/cyclic/GroupEmailAddress.java b/solutions/code/tutorialquestions/questiondc38/cyclic/GroupEmailAddress.java index 7d409dc..d52b415 100755 --- a/solutions/code/tutorialquestions/questiondc38/cyclic/GroupEmailAddress.java +++ b/solutions/code/tutorialquestions/questiondc38/cyclic/GroupEmailAddress.java @@ -5,11 +5,11 @@ public class GroupEmailAddress extends EmailAddress { - private Set members; + private final Set members; public GroupEmailAddress(String identifier) { super(identifier); - members = new HashSet(); + members = new HashSet<>(); } public void addEmailAddress(EmailAddress emailAddress) { @@ -19,7 +19,7 @@ public void addEmailAddress(EmailAddress emailAddress) { @Override protected Set getTargets(Set alreadySeen) { - Set result = new HashSet(); + Set result = new HashSet<>(); if (alreadySeen.contains(this)) { return result; diff --git a/solutions/code/tutorialquestions/questiondc38/cyclic/IndividualEmailAddress.java b/solutions/code/tutorialquestions/questiondc38/cyclic/IndividualEmailAddress.java index 375d1f4..f6168c5 100755 --- a/solutions/code/tutorialquestions/questiondc38/cyclic/IndividualEmailAddress.java +++ b/solutions/code/tutorialquestions/questiondc38/cyclic/IndividualEmailAddress.java @@ -11,7 +11,7 @@ public IndividualEmailAddress(String identifier) { @Override protected Set getTargets(Set alreadySeen) { - Set result = new HashSet(); + Set result = new HashSet<>(); result.add(this); return result; } diff --git a/solutions/code/tutorialquestions/questiondc38/cyclic/Mailbox.java b/solutions/code/tutorialquestions/questiondc38/cyclic/Mailbox.java index 63211ec..9317c34 100755 --- a/solutions/code/tutorialquestions/questiondc38/cyclic/Mailbox.java +++ b/solutions/code/tutorialquestions/questiondc38/cyclic/Mailbox.java @@ -2,7 +2,7 @@ public class Mailbox { - private String mailboxIdentifier; + private final String mailboxIdentifier; public Mailbox(String mailboxIdentifier) { this.mailboxIdentifier = mailboxIdentifier; diff --git a/solutions/code/tutorialquestions/questiondd4c/AlarmClock.java b/solutions/code/tutorialquestions/questiondd4c/AlarmClock.java index a971d1f..cc6257e 100755 --- a/solutions/code/tutorialquestions/questiondd4c/AlarmClock.java +++ b/solutions/code/tutorialquestions/questiondd4c/AlarmClock.java @@ -2,7 +2,7 @@ public class AlarmClock extends Clock { - private int alarmTimeSecondsSinceMidnight; + private final int alarmTimeSecondsSinceMidnight; private boolean alarmSounding = false; diff --git a/solutions/code/tutorialquestions/questiondd4c/Clock.java b/solutions/code/tutorialquestions/questiondd4c/Clock.java index 78ff94e..548e2bf 100755 --- a/solutions/code/tutorialquestions/questiondd4c/Clock.java +++ b/solutions/code/tutorialquestions/questiondd4c/Clock.java @@ -48,11 +48,9 @@ public String toString() { int ss = secondsSinceMidnight % SECONDS_IN_A_MINUTE; - String result = padding(hh) + hh + ":" + return padding(hh) + hh + ":" + padding(mm) + mm + ":" + padding(ss) + ss; - - return result; } diff --git a/solutions/code/tutorialquestions/questiondd4c/RadioAlarmClock.java b/solutions/code/tutorialquestions/questiondd4c/RadioAlarmClock.java index a4e6ea5..ebeeb29 100755 --- a/solutions/code/tutorialquestions/questiondd4c/RadioAlarmClock.java +++ b/solutions/code/tutorialquestions/questiondd4c/RadioAlarmClock.java @@ -2,7 +2,7 @@ public class RadioAlarmClock extends AlarmClock { - private RadioStation station; + private final RadioStation station; public RadioAlarmClock(int time, int alarm, RadioStation station) { super(time, alarm); diff --git a/solutions/code/tutorialquestions/questiondd4c/RadioStation.java b/solutions/code/tutorialquestions/questiondd4c/RadioStation.java index a1bb093..4c9f5a5 100755 --- a/solutions/code/tutorialquestions/questiondd4c/RadioStation.java +++ b/solutions/code/tutorialquestions/questiondd4c/RadioStation.java @@ -5,17 +5,12 @@ public enum RadioStation { None, Radio4, PlanetRock, FiveLive, JazzFM; public String getNoise() { - switch (this) { - case Radio4: - return "Blah, blah, blah"; - case PlanetRock: - return "Rock rock 'til you drop"; - case FiveLive: - return "...and it's a GOAL!!"; - case JazzFM: - return "Ba di bah, ba do bop"; - default: - return ""; - } + return switch (this) { + case None -> ""; + case Radio4 -> "Blah, blah, blah"; + case PlanetRock -> "Rock rock 'til you drop"; + case FiveLive -> "...and it's a GOAL!!"; + case JazzFM -> "Ba di bah, ba do bop"; + }; } } diff --git a/solutions/code/tutorialquestions/questione6fd/BitSet64.java b/solutions/code/tutorialquestions/questione6fd/BitSet64.java index 79ddbfb..bf9baef 100755 --- a/solutions/code/tutorialquestions/questione6fd/BitSet64.java +++ b/solutions/code/tutorialquestions/questione6fd/BitSet64.java @@ -51,16 +51,16 @@ public int maxStorableValue() { @Override public String toString() { - String result = "{ "; + final StringBuilder result = new StringBuilder("{ "); boolean first = true; for (int x = 0; inRange(x); x++) { if (contains(x)) { if (first) { first = false; } else { - result += ", "; + result.append(", "); } - result += x; + result.append(x); } } return result + " }"; diff --git a/solutions/code/tutorialquestions/questione6fd/BitSet8.java b/solutions/code/tutorialquestions/questione6fd/BitSet8.java index f2bcd06..8f9b6d0 100755 --- a/solutions/code/tutorialquestions/questione6fd/BitSet8.java +++ b/solutions/code/tutorialquestions/questione6fd/BitSet8.java @@ -51,16 +51,16 @@ public int maxStorableValue() { @Override public String toString() { - String result = "{ "; + final StringBuilder result = new StringBuilder("{ "); boolean first = true; for (int x = 0; inRange(x); x++) { if (contains(x)) { if (first) { first = false; } else { - result += ", "; + result.append(", "); } - result += x; + result.append(x); } } return result + " }"; diff --git a/solutions/code/tutorialquestions/questione6fd/BitSetArray.java b/solutions/code/tutorialquestions/questione6fd/BitSetArray.java index e09fc0f..ea587cb 100755 --- a/solutions/code/tutorialquestions/questione6fd/BitSetArray.java +++ b/solutions/code/tutorialquestions/questione6fd/BitSetArray.java @@ -2,8 +2,8 @@ public class BitSetArray implements BitSet { - private int maxValue; - private long[] representation; + private final int maxValue; + private final long[] representation; public BitSetArray(int maxValue) { if (maxValue < 0) { @@ -38,7 +38,7 @@ public boolean contains(int value) { public void intersectWith(BitSet other) { if (other instanceof BitSetArray) { for (int i = 0; - i <= Math.min(maxStorableValue(), ((BitSetArray) other).maxStorableValue()) / Long.SIZE; + i <= Math.min(maxStorableValue(), other.maxStorableValue()) / Long.SIZE; i++) { representation[i] &= ((BitSetArray) other).representation[i]; } @@ -58,16 +58,16 @@ public int maxStorableValue() { @Override public String toString() { - String result = "{ "; + final StringBuilder result = new StringBuilder("{ "); boolean first = true; for (int x = 0; inRange(x); x++) { if (contains(x)) { if (first) { first = false; } else { - result += ", "; + result.append(", "); } - result += x; + result.append(x); } } return result + " }"; diff --git a/solutions/code/tutorialquestions/questionf763/Demo.java b/solutions/code/tutorialquestions/questionf763/Demo.java index acf3a17..3fa3346 100755 --- a/solutions/code/tutorialquestions/questionf763/Demo.java +++ b/solutions/code/tutorialquestions/questionf763/Demo.java @@ -18,11 +18,11 @@ public static void main(String[] args) { List> bigTreeNodes = buildBinaryTree(BIG_TREE_DEPTH); List> smallTreeNodes = buildBinaryTree(SMALL_TREE_DEPTH); - Set> heapObjects = new HashSet>(); + Set> heapObjects = new HashSet<>(); heapObjects.addAll(bigTreeNodes); heapObjects.addAll(smallTreeNodes); - Set> activeObjectRoots = new HashSet>(); + Set> activeObjectRoots = new HashSet<>(); activeObjectRoots.add(bigTreeNodes.get(0)); System.out.println("Before garbage collection:"); @@ -59,9 +59,9 @@ private static void displayMemory(Set> heapObjects, private static List> buildBinaryTree(int depth) { - List> result = new ArrayList>(); + List> result = new ArrayList<>(); - result.add(new GraphNode()); + result.add(new GraphNode<>()); result.get(0).setKey(getNextId()); if (depth > 1) { diff --git a/solutions/code/tutorialquestions/questionf763/GarbageCollector.java b/solutions/code/tutorialquestions/questionf763/GarbageCollector.java index aa49563..a754b73 100755 --- a/solutions/code/tutorialquestions/questionf763/GarbageCollector.java +++ b/solutions/code/tutorialquestions/questionf763/GarbageCollector.java @@ -11,9 +11,9 @@ public class GarbageCollector { public void collectGarbage(Set> heapObjects, Set> activeObjectRoots) { - Set> reachable = new HashSet>(); + Set> reachable = new HashSet<>(); - Deque> stack = new ArrayDeque>(); + Deque> stack = new ArrayDeque<>(); for (GraphNode node : activeObjectRoots) { stack.push(node); diff --git a/solutions/code/tutorialquestions/questionf79b/PerfectPalindromicCubes.java b/solutions/code/tutorialquestions/questionf79b/PerfectPalindromicCubes.java index 3080cd1..13039c8 100755 --- a/solutions/code/tutorialquestions/questionf79b/PerfectPalindromicCubes.java +++ b/solutions/code/tutorialquestions/questionf79b/PerfectPalindromicCubes.java @@ -2,13 +2,13 @@ public class PerfectPalindromicCubes { - private static boolean isPalindrome(String s) { - if (s.length() == 0 || s.length() == 1) { + private static boolean isPalindrome(String number) { + if (number.length() == 0 || number.length() == 1) { return true; } - return s.charAt(0) == s.charAt(s.length() - 1) - && isPalindrome(s.substring(1, s.length() - 1)); + return number.charAt(0) == number.charAt(number.length() - 1) + && isPalindrome(number.substring(1, number.length() - 1)); } /** diff --git a/solutions/code/tutorialquestions/questionf7c3/PigLatin.java b/solutions/code/tutorialquestions/questionf7c3/PigLatin.java index a8324b0..897cc6b 100755 --- a/solutions/code/tutorialquestions/questionf7c3/PigLatin.java +++ b/solutions/code/tutorialquestions/questionf7c3/PigLatin.java @@ -11,11 +11,11 @@ public class PigLatin { */ public static void main(String[] args) throws IOException { - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + final BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - String line = br.readLine(); + final StringBuilder stringBuilder = new StringBuilder(); - StringBuilder stringBuilder = new StringBuilder(); + String line = br.readLine(); while (line != null) { stringBuilder.append(translateLineToPigLatin(line)); @@ -28,18 +28,18 @@ public static void main(String[] args) throws IOException { private static String translateLineToPigLatin(String line) { - StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); - String word = ""; + StringBuilder word = new StringBuilder(); for (int i = 0; i < line.length(); i++) { if (Character.isLetterOrDigit(line.charAt(i))) { - word += line.charAt(i); + word.append(line.charAt(i)); } else { if (word.length() > 0) { - builder.append(translateToPigLatin(word)); - word = ""; + builder.append(translateToPigLatin(word.toString())); + word = new StringBuilder(); } builder.append(line.charAt(i)); } @@ -67,23 +67,15 @@ private static String translateToPigLatin(String word) { return (Character.isUpperCase(word.charAt(0)) ? Character .toUpperCase(word.charAt(1)) : word.charAt(1)) - + word.substring(2, word.length()) + + word.substring(2) + Character.toLowerCase(word.charAt(0)) + "ay"; } private static boolean isVowel(char c) { - - switch (Character.toLowerCase(c)) { - case 'a': - case 'e': - case 'i': - case 'o': - case 'u': - return true; - default: - return false; - } - + return switch (Character.toLowerCase(c)) { + case 'a', 'e', 'i', 'o', 'u' -> true; + default -> false; + }; } } \ No newline at end of file diff --git a/solutions/code/tutorialquestions/questionfe94/Example.java b/solutions/code/tutorialquestions/questionfe94/Example.java new file mode 100755 index 0000000..61ffb8f --- /dev/null +++ b/solutions/code/tutorialquestions/questionfe94/Example.java @@ -0,0 +1,76 @@ +package tutorialquestions.questionfe94; + +import java.util.List; +import java.util.stream.Collectors; + +public class Example { + + static List reverseEachString(List input) { + return input + .stream() + .map(StringBuilder::new) + .map(StringBuilder::reverse) + .map(StringBuilder::toString) + .collect(Collectors.toList()); + } + + static List reverseEachStringMonolithic(List input) { + return input + .stream() + .map(item -> new StringBuilder(item).reverse().toString()) + .collect(Collectors.toList()); + } + + static List sqrtsOfFirstDigits(List input) { + return input + .stream() + .filter(item -> item.length() > 0) + .filter(item -> Character.isDigit(item.charAt(0))) + .map(item -> Integer.valueOf(item.substring(0, 1))) + .map(Math::sqrt) + .collect(Collectors.toList()); + } + + static List sqrtsOfFirstDigitsMonolithic(List input) { + return input + .stream() + .filter(item -> item.length() > 0 && Character.isDigit(item.charAt(0))) + .map(item -> Math.sqrt(Integer.parseInt(item.substring(0, 1)))) + .collect(Collectors.toList()); + } + + public static void main(String[] args) { + + final List strings = List.of( + "1astring", "2anotherstring", "ant", "eater", "-1nofirstdigit", "9anotherstring", + "88only8getsrooted"); + + final List expectedReversed = List.of( + "gnirtsa1", "gnirtsrehtona2", "tna", "retae", "tigidtsrifon1-", "gnirtsrehtona9", + "detoorsteg8ylno88"); + + final List expectedSqrtsOfFirstDigits = List.of(Math.sqrt(1), Math.sqrt(2), + Math.sqrt(9), Math.sqrt(8)); + + final List reversed1 = reverseEachString(strings); + final List reversed2 = reverseEachStringMonolithic(strings); + + final List sqrtsOfFirstDigits1 = sqrtsOfFirstDigits(strings); + final List sqrtsOfFirstDigits2 = sqrtsOfFirstDigitsMonolithic(strings); + + System.out.println("Two ways of reversing " + strings + " give " + reversed1 + " and " + + reversed2); + + System.out.println("Two ways of taking the square roots of the first digits of any strings in " + + strings + " that start with digits give " + sqrtsOfFirstDigits1 + " and " + + sqrtsOfFirstDigits2); + + assert expectedReversed.equals(reversed1); + assert expectedReversed.equals(reversed2); + + assert expectedSqrtsOfFirstDigits.equals(sqrtsOfFirstDigits1); + assert expectedSqrtsOfFirstDigits.equals(sqrtsOfFirstDigits2); + + } + +} diff --git a/solutions/d363.md b/solutions/d363.md index c5f43ea..42e9538 100644 --- a/solutions/d363.md +++ b/solutions/d363.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [d363](../questions/d363): *Bloated person* +## Solution to [d363](../questions/d363.md): *Bloated person* See code at `solutions/code/tutorialquestions/questiond363` diff --git a/solutions/d3f5.md b/solutions/d3f5.md new file mode 100755 index 0000000..8dd7f7e --- /dev/null +++ b/solutions/d3f5.md @@ -0,0 +1,17 @@ +[Back to questions](../README.md) + +## Solution to [d3f5](../questions/d3f5.md): *Streams and downcasting* + +See code at `solutions/code/tutorialquestions/questiond3f5` + +Observe the use of `filter` to first filter the stream to get just those elements of type `Integer`, and then `map` to actually get a `Stream` instead of a `Stream`. The reason we need to use `map` after `filter`, even though `map` is a no-op, is that `filter` takes a `Stream` and returns a `Stream`, so given a `Stream` it returns a `Stream`. If we removed the `map` step, the second `filter`, where we filter those elements whose values are not positive, would not compile since we cannot ask "`n > 0`" when `n` is an arbitrary `Number`. + +We are not allowed to invoke `restrictToPositiveIntegers` on a `Stream` or a `Stream` because in Java, if `B` is a subtype of `A` (e.g. `B` is `Float` and `A` is `Number`), it does not follow that `C` is a subtype of `C` -- in particular it does not follow that `Stream` is a subtype of `Stream`, so `Stream` is not a subtype of `Stream`. + +The method `restrictToPositiveIntegersBoundedWildcard` has this signature: + + static Stream restrictToPositiveIntegersBoundedWildcard(Stream numbers); + +The use of a *bounded wildcard* in the signature of `restrictToPositiveIntegersBoundedWildcard` solves the problem: `Stream` is compatible with `Stream` and `Stream` because `Float` extends `Number` and `Integer` extends `Number`. + +Have a look at the `main` method in the solution and check that your solution exhibits similar behaviour. diff --git a/solutions/dc38.md b/solutions/dc38.md index 9cd68c0..4d98be6 100644 --- a/solutions/dc38.md +++ b/solutions/dc38.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [dc38](../questions/dc38): *Email management system* +## Solution to [dc38](../questions/dc38.md): *Email management system* See code at `solutions/code/tutorialquestions/questiondc38` diff --git a/solutions/dd4c.md b/solutions/dd4c.md index 8f69c8a..aa5effa 100644 --- a/solutions/dd4c.md +++ b/solutions/dd4c.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [dd4c](../questions/dd4c): *Clocks* +## Solution to [dd4c](../questions/dd4c.md): *Clocks* See code at `solutions/code/tutorialquestions/questiondd4c` diff --git a/solutions/e093.md b/solutions/e093.md index eeff6aa..893b56d 100644 --- a/solutions/e093.md +++ b/solutions/e093.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [e093](../questions/e093): *Average of numbers* +## Solution to [e093](../questions/e093.md): *Average of numbers* See code at `solutions/code/tutorialquestions/questione093` diff --git a/solutions/e6fd.md b/solutions/e6fd.md index 907847f..3750e31 100644 --- a/solutions/e6fd.md +++ b/solutions/e6fd.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [e6fd](../questions/e6fd): *Bit sets* +## Solution to [e6fd](../questions/e6fd.md): *Bit sets* See code at `solutions/code/tutorialquestions/questione6fd` diff --git a/solutions/e93f.md b/solutions/e93f.md index a853504..c607da5 100644 --- a/solutions/e93f.md +++ b/solutions/e93f.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [e93f](../questions/e93f): *Apparent and actual types* +## Solution to [e93f](../questions/e93f.md): *Apparent and actual types* See code at `solutions/code/tutorialquestions/questione93f` diff --git a/solutions/f763.md b/solutions/f763.md index 78449a2..e440ae7 100644 --- a/solutions/f763.md +++ b/solutions/f763.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [f763](../questions/f763): *Simulating garbage collection* +## Solution to [f763](../questions/f763.md): *Simulating garbage collection* See code at `solutions/code/tutorialquestions/questionf763` diff --git a/solutions/f79b.md b/solutions/f79b.md index 8d27522..023f09b 100755 --- a/solutions/f79b.md +++ b/solutions/f79b.md @@ -1,18 +1,24 @@ [Back to questions](../README.md) -## Solution to [f79b](../questions/f79b): *Perfect palindromic cubes* +## Solution to [f79b](../questions/f79b.md): *Perfect palindromic cubes* See code at `solutions/code/tutorialquestions/questionf79b` The solution involves a method: ``` -static boolean isPalindrome(String s); +static boolean isPalindrome(String number); ``` -which determines whether the `String` parameter `s` is a palindrome. The method is recursive. As a base case, strings of length 0 and 1 are (trivially) palindromes; we use the method `length()` of `String` to determine this. -For a string of greater length, we check whether its first and last characters are the same. This is achieved using the `charAt(int i)` method, -which returns the character at position `i` of the string. +which determines whether the `String` parameter `number` (named so as in this question it is intended to store the String representation of a number) is a palindrome. The method is recursive. As a base case, strings of length 0 and 1 are (trivially) palindromes; we use the method `length()` of `String` to determine this. +For a string of greater length, we check whether its first and last characters are the same. This is achieved using the `charAt(int index)` method, +which returns the character at position `index` of the string. Armed with `isPalindrome`, we enumerate the first 2000 cubes using a `for` loop. For each cube, we turn it into a string using `String.valueOf`, and test the resulting string using `isPalindrome`. + +An alternative approach to `isPalindrome` is to take the number as an `int` and use arithmetic operations (based on the `/` and `%` operators) to determine whehter successive pairs of digits are equal, working from the outside in. However, such a solution is less readable than the simple String-based solution given here, and it is best to favour readability over efficienty when programming, unless there is an urgent need for efficiency. + +Regarding the problem of running the program for larger numbers: integers in Java are 32-bit, and the largest positive integer representable in Java is 231-1 = 2147483647. The largest integer that, when cubed, is less than or equal to this limit, is 1290: 12903 = 2146689000. Although mathematically, 12913 = 2151685171, when computed in a Java program one gets the answer -2143282125, which is 2151685171 - 232. This is because the result wraps around. + +Representing integers using the java.math.BigInteger class would avoid this problem - try it out! diff --git a/solutions/f7c3.md b/solutions/f7c3.md index 330b0b3..ca7a96e 100644 --- a/solutions/f7c3.md +++ b/solutions/f7c3.md @@ -1,6 +1,6 @@ [Back to questions](../README.md) -## Solution to [f7c3](../questions/f7c3): *Pig Latin* +## Solution to [f7c3](../questions/f7c3.md): *Pig Latin* See code at `solutions/code/tutorialquestions/questionf7c3` diff --git a/solutions/fe94.md b/solutions/fe94.md new file mode 100755 index 0000000..72ffb46 --- /dev/null +++ b/solutions/fe94.md @@ -0,0 +1,11 @@ +[Back to questions](../README.md) + +## Solution to [fe94](../questions/fe94.md): *Using Stream.map and Stream.filter* + +See code at `solutions/code/tutorialquestions/questionfe94` + +Compare your solution to the sample answer. + +In `reverseEachString`, note the syntax `StringBuilder::new` for mapping the constructor of `StringBuilder` that takes a `String` argument over a stream of `String`s to get a stream of `StringBuilder`s. + +Think about the differences in readability between the standard and monolithic versions you have implemented, and whether you have a preference. \ No newline at end of file