2

I just want to ask, if it is possible to check if a void method "cancelled" itself by calling return;?

For example in my main I call calculate(myArray);, which is defined as follows:

public static void calculate(Object[] array) {
    if (array == null)
        return;
    // do stuff
}

Is their a way to know, if it returned or not? My thoughts were making a "global" boolean which is changed to true right before we return and then check its value in main or just change the return type to something like int and when it returned at the beginning we use return -1; and at the end of the method return 0;

Both is possible but I think neither of them is very good style. Is there an alternative?

Unihedron
  • 10,902
  • 13
  • 62
  • 72
Frozn
  • 539
  • 1
  • 8
  • 17
  • 3
    make it return a boolean? – Tim Nov 03 '14 at 15:40
  • 7
    `throw new NullPointerException("Array is null");`? – TNT Nov 03 '14 at 15:40
  • why is it not a "good style" ? – Chiseled Nov 03 '14 at 15:41
  • No Java has no such feature built in. The only way to "handle" such situations is by logic indicated in the comments/ answers (my personal favorite is the NullPointerException if the method must stay void under any circumstances – JBA Nov 03 '14 at 15:43
  • Unit tests or a debugger are your friend here. Debugger allows you to step through and see what the function does. A unit test would allow you to try different parameters and see what result is left over compared to what you expect it to be. – FelixMarcus Nov 03 '14 at 15:45
  • 1
    If the array is not permitted to be null by the method's contract, don't do that defensive check and throw the appropriate NPE implicitly when you access it. – chrylis -cautiouslyoptimistic- Nov 03 '14 at 15:49
  • You're all right. Why do I want to use integers. Just forgot, that there is this data type :D The way with exceptions is also a good way, always handling exceptions but never throwing some myself. Thanks! – Frozn Nov 03 '14 at 17:49

3 Answers3

5

You are right that the practices you described are considered bad in Java (and other modern languages).

The most common acceptable practices for your scenario are:

  • Make the method throw an exception. Do this if the "failing" code path shouldn't happen under normal circumstances.
  • Make the method's return type bool to indicate success or failure. Do this if the "failing" code path can happen under normal circumstances as well.
Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
3

No, you cannot. From The Oracle Java tutorials - Returning a Value from a Method:

Any method declared void doesn't return a value. It does not need to contain a return statement, but it may do so. In such a case, a return statement can be used to branch out of a control flow block and exit the method and is simply used like this:

return;

There is no way from method invocation to determine if the void method was completed by a fall-through block or a return; statement.

Most other methods includes a return type of boolean and returns false when something went wrong, or simply throws an IllegalArgumentException.

Community
  • 1
  • 1
Unihedron
  • 10,902
  • 13
  • 62
  • 72
  • Like what Theodoros Chatzigiannakis said, but with more explanation from the official site. Thank you too for that clarification. – Frozn Nov 03 '14 at 17:52
3

You can utilize publisher - listener pattern :)

import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;

public class Sample {

    private interface Event {

    }

    private static class ExitEvent implements Event {

    }

    private static class SucceedEvent implements Event {

    }

    private interface EventListener {
        void eventPerformed(Event e);
    }

    private static List<EventListener> listeners = new LinkedList<EventListener>();

    private static void addActionListener(EventListener l) {
        listeners.add(l);
    }

    private static void fireEvent(Event event) {
        for (EventListener l : listeners) {
            l.eventPerformed(event);
        }
    }

    public static void calculate(Object[] array) {
        if (array == null) {
            fireEvent(new ExitEvent());
            return;
        }

        fireEvent(new SucceedEvent());
    }

    public static void main(String[] args) {

        addActionListener(new EventListener() {

            public void eventPerformed(Event e) {

                if (e instanceof ExitEvent) {
                    System.out.println("Exit");
                } else if (e instanceof SucceedEvent) {
                    System.out.println("Success");
                }

            }

        });

        calculate(null);
        calculate(new Object[] {});

    }

}

Output:

Exit
Success

You can go much farther and remove those ugly ifs, by utilizing visitor pattern

import java.util.LinkedList;
import java.util.List;

public class Sample {

    private interface EventVisitor {
        void visit(ExitEvent event);

        void visit(SucceedEvent event);
    }

    private interface Event {
        void accept(EventVisitor visitor);
    }

    private static class ExitEvent implements Event {

        public void accept(EventVisitor visitor) {
            visitor.visit(this);
        }

    }

    private static class SucceedEvent implements Event {

        public void accept(EventVisitor visitor) {
            visitor.visit(this);
        }

    }

    private interface EventListener {
        void eventPerformed(Event e);
    }

    private static List<EventListener> listeners = new LinkedList<EventListener>();

    private static void addActionListener(EventListener l) {
        listeners.add(l);
    }

    private static void fireEvent(Event event) {
        for (EventListener l : listeners) {
            l.eventPerformed(event);
        }
    }

    public static void calculate(Object[] array) {
        if (array == null) {
            fireEvent(new ExitEvent());
            return;
        }

        fireEvent(new SucceedEvent());
    }

    public static void main(String[] args) {

        addActionListener(new EventListener() {

            public void eventPerformed(Event e) {

                e.accept(new EventVisitor() {

                    public void visit(SucceedEvent event) {
                        System.out.println("Success");

                    }

                    public void visit(ExitEvent event) {
                        System.out.println("Exit");

                    }
                });

            }

        });

        calculate(null);
        calculate(new Object[] {});

    }

}

Output:

Exit
Success
slavik
  • 1,223
  • 15
  • 17
  • Unless returning early is exceptional behavior is some way (something that should almost never happen), the patterns in this solution are better practice than throwing an exception. – ssube Nov 03 '14 at 19:57
  • This is a great idea and is well-fit for this case - upvoted :) Though additional checks should be done to assert thread-safety, but the demonstration is clear and helpful. Well done! – Unihedron Nov 04 '14 at 09:23