2 ms·
I agree with you on your first statement. Exceptions for control flow is an awful API. I also wholeheartedly agree with your comments that nullability should
by dfe 2y ago
I agree with you on your first statement. Exceptions for control flow is an awful API.
I also wholeheartedly agree with your comments that nullability should be a first-class language feature, part of the type system. I think what you describe is one of the active JEPs.
* Plain old String is "I don't know if it's nullable or not, so I'll let you dereference it without checking, but I may issue a warning.
* String! is "You're telling me it cannot be null so I will enforce that it is not null on the way in (e.g. when converting from String) and will issue no warning on the way out because it cannot be null.
* Finally, String? is "You're explicitly telling me it can be null, so I will force you to do a null check before converting to a String!"
But that's only part of it. I think Java desperately needs a ?. operator (Optional.map but without the Optional). I also think it needs a ?? operator (Optional.orElse but without the Optional).
So far I think Optional is more of a detriment to Java than a benefit. It feels like it was hacked in because without it some of the Stream APIs would be nightmarish given Java's current type system, and getting streams into the standard library API was too important a feature to wait for fixing the long-standing issues with nullability.
The only thing I disagree with you on is I do think there is some merit to checked exceptions when used sparingly. Capturing the idea that a method can fail for a reason that has to do with the program's input or environment (checked exception) vs. a reason that has to do with the program's code and cannot be solved without changing the program's code (RuntimeException) is a pretty neat thing.
I think the Streams API could have easily implemented terminal operations like forEach(ThrowingConsumer<E,X>). This could still be added.
I also think that the <X> ... throws X pattern should accommodate a union type like IOException|ParseException and that this should be inferred so that in this example of a throwing Consumer, whatever checked exceptions the method throws simply become the checked exceptions of the forEach method.
Conceptually, these are straightforward ideas. I suspect the limiting factor is figuring out how in the world to actually implement what I just described.