Last Check: Mar 22 2026
<aside> ❗
If you find my comment for your submission matching points in this section, be careful!
</aside>
Note Producer Extends Consumer Super
| Maybe<T> filter(BooleanCondition<? super T> bc); |
|---|
| <S> Maybe<S> map(Transformer<? super T, ? extends S> transformer); |
| <S> Maybe<S> flatMap(Transformer<? super T, ? extends Maybe<? extends S>> transformer); |
| T orElse(T t); |
| T orElseGet(Producer<? extends T> producer); |
| void ifPresent(Consumer<? super T> consumer); |
None doesn’t need to have item or val (what ever name you give to the internal value of your Maybe)
When you try to get() from None, it should throw NoSuchElementException instead of return null or something. I was surprised the auto-grading script does not catch this.
Your None and Some as nested class should have access modifier private. See problem statement:
The types None and Some are internal implementation details of Maybe and must not be used directly. For instance, clients must not be able to declare a variable of type Maybe.Some.
Without private it is possible to have Maybe.Some and Maybe.None, which leaks information on implementation details of Maybe
Add on to point above, your nested class should also be declared with final to prevent subtypes from overriding behavior of None and Some. The complete way to define Some would be private static final class Some<T> extends Maybe<T>
Some suppress warning has a larger scope than expected. you only need to suppress the assignment (although sometimes you directly return and don't use any assignment, then you suppress the whole method). The best way is
public static <T> Maybe<T> none() {
@SuppressWarnings("unchecked")
Maybe<T> res = (Maybe<T>) NONE; // ONLY SUPPRESS THIS LINE
return res;
}
you should NEVER suppress rawtype because you can always replace rawtype with unbounded wildcard. See https://nus-cs2030s.github.io/2526-s2/26-wildcard.html#revisiting-raw-types.
None::flatMap/map/filter: No need for SuppressWarnings("unchecked") if you return Maybe.none()
If your filter use BooleanCondition<T> pred , it is not desirable. BooleanCondition<? super T> pred is more flexible and generally preferred. If you use BooleanCondition<T> pred, only with exact matching on BC type will the code compile. Suppose we have a BC that check on all Object. Now it cannot be used to filter a Maybe of String. See code below
// Suppose u have
Maybe<String> maybeStr = Maybe.of("my maybe string");
// With BooleanCondition<? super T> pred, ALL of these work:
maybeStr.filter(new BooleanCondition<String>() {...})
maybeStr.filter(new BooleanCondition<Object>() {...})
// With BooleanCondition<T> pred, only exact match works:
maybeStr.filter(new BooleanCondition<String>() {...})
maybeStr.filter(new BooleanCondition<Object>() {...}) // CANNOT COMPILE
If NONE (the singleton) is put in nested class None, it is not desirable. It would be better to be put in Maybe. NONE represents the singleton instance for all parameterizations of Maybe. It's shared across Maybe. This is a property of the Maybe abstraction, not specific to the None implementation. Clients call Maybe.none(), not None.getInstance() or similar. If NONE were in None, you'd have awkward coupling where Maybe.none() reaches into None's internals
Some::orElse: No need to distinguish whether the value inside is null as you always just return that value, regardless
Some::orElseGet: You should not activate the producer in Some. The producer is only used in None. If the value in Some is null, then simply return the Some of null AS IT IS.
Some of you declare NONE as of type None or Maybe<Object> but the optimal would be Maybe<?> .
Problem with None : Exposes implementation detail (None) in the field type; If None is package-private, this won't compile in other packages
Problem with Maybe<Object> : Wrong semantics, None doesn't contain Object, it contains nothing. Type parameter is a lie, there is no T .
// BAD
private static final None NONE = new None();
private static final Maybe<Object> NONE = new None();
// GOOD
private static final Maybe<?> NONE = new None();
Don’t throw NullPointerException explicitly in code. It is handled by JVM automatically as it is runtime exception. Also see https://nus-cs2030s.github.io/2526-s2/22-exception.html for revision.
public abstract. In Java interface, all methods are implicitly public (before Java 9, they were also implicitly abstract unless marked default or static). Also, interface methods are always accessible to implementers, so they must be public.