Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPE in max() and min() #1482

Closed
eirikm opened this issue Aug 11, 2016 · 8 comments
Closed

NPE in max() and min() #1482

eirikm opened this issue Aug 11, 2016 · 8 comments

Comments

@eirikm
Copy link

eirikm commented Aug 11, 2016

Using min or max on a list containing a null value will either produce a NPE or Option.none:

    @Test
    public void nullPointerExceptionInMinAndMax() {
        Integer one = 1;
        Integer zero = 0;
        Integer nullInteger = null;

        try {
            List<Integer> nullSecond = List.of(zero, nullInteger, one);
            nullSecond.min();
            nullSecond.max();
        } catch (NullPointerException e) {
            System.out.println("Boooo. Gives NPE but should give min == zero && max == one. Due to o1.compareTo(o2) in max and min");
        }

        List<Integer> nullAsHead = List.of(nullInteger, zero, one);
        System.out.println("nullAsHead.min() = " + nullAsHead.min());
        System.out.println("nullAsHead.max() = " + nullAsHead.max());
        System.out.println("Boo gives None in both situations. should give min == zero && max = one. Due to the fact: !(list.head() instanceof Comparable))");

        try {
            List<Integer> nullAtEnd = List.of(zero, one, nullInteger);
            nullAtEnd.min();
            nullAtEnd.max();
        } catch (NullPointerException e) {
            System.out.println("Boooo. Gives NPE but should give min == zero && max == one. Due to o1.compareTo(o2) in max and min");
        }
    }
@danieldietrich
Copy link
Contributor

I'm not sure about allowing null values. An alternative is to prohibit null as part of the interface documentation.

In native Java the min and max functions are only available in primitive Streams, like IntStream. My vision is to further restrict the types when future Java versions allow us to do so. Currently an extension of the type system is investigated as part of project Valhalla:

valhalla-partial-methods

For now I suggest to filter the values in order to get sure null values are handled properly:

List.of(null, 0, null, 1, null) . filter(Predicates::isNotNull) . min();

I will update the min/max documentation accordingly.

@danieldietrich danieldietrich added this to the 2.1.0 milestone Aug 11, 2016
@l0rinc
Copy link
Contributor

l0rinc commented Aug 12, 2016

I would ban null values everywhere, muhahahaha :trollface:
But if that's not possible, we should at least do something more meaningful than an NPE :/

@danieldietrich
Copy link
Contributor

Arithmetic operations should only process on defined element.

E.g. 1 + null is not 1. I would say it is undefined because our arithmetic has no notion for adding an element outside the set of ints to an int.

So why max(1, null) should be 1?

A healthy codebase does not implement additional logical branches for every special case and his dog :-) We should do it as straight forward as possible.

Therefore we will not include special null handling here.

@danieldietrich
Copy link
Contributor

I would ban null values everywhere, muhahahaha :trollface:

YEAH - and the user has to SUFFER if he uses null values, MUHAHAHAHA 👹

@eirikm
Copy link
Author

eirikm commented Aug 14, 2016

Even if max(1, null) shouldn’t be 1 it would be reasonable to assume that
max(1, null) would provide the same result/error as max(null, 1), wouldn’t it?

Eirik

On 14 Aug 2016, at 16:28, Daniel Dietrich notifications@github.com wrote:

Arithmetic operations should only process on defined element.

E.g. 1 + null is not 1. I would say it is undefined because our arithmetic has no notion for adding an element outside the set of ints to an int.

So why max(1, null) should be 1?

A healthy codebase does not implement additional logical branches for every special case and his dog :-) We should do it as straight forward as possible.

Therefore we will not include special null handling here.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub #1482 (comment), or mute the thread https://github.com/notifications/unsubscribe-auth/AAezuzLM9W5N1CQ4oDvIrJiwA8VAkNXsks5qfyYjgaJpZM4Jh7WK.

@danieldietrich
Copy link
Contributor

@eirikm yes, that's right. We should throw something like an ArithmeticException in such cases. Thanks for the hint!

@danieldietrich danieldietrich modified the milestones: 2.2.0, 2.1.0 Aug 26, 2016
@danieldietrich danieldietrich modified the milestones: 2.1.0, 2.2.0 Oct 23, 2016
@danieldietrich danieldietrich modified the milestones: 2.0.5, 2.1.0 Nov 2, 2016
@danieldietrich
Copy link
Contributor

We can't easily intercept a min/max computation and map a NPE to an ArithmeticException. This is because min/max internally call minBy/maxBy, which take a custom Comparator. A custom Comparator can throw a NPE for another reason, so we can't catch the NPE and rethrow an ArtithmeticException.

Therefore we don't do it more complicated than it should be. Plain Java acts like this:

// throws NullPointerException
Stream.of(null, 1).min(Integer::compare);

// throws NullPointerException
Stream.of(1, null).min(Integer::compare);

We will act the same way. This is just one extra check in min()/max(), if the head element is null.

@danieldietrich
Copy link
Contributor

The simple solution works for all collections but TreeSet/RedBlackTree. Needs further investigation.

Btw - all SortedMap and SortedSet implementations should at least override min() because that is the head() element (if present).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants