0

For some background, I'm currently on chapter 8 in my book, we finished talking about arraylists, arrays, if statements, loops etc. Now this part of the book talks about call by reference,value and some other pretty neat things that seem odd to me at first.I've read What situation to use static and some other SO questions, and learned quite a bit as well.

Consider the following example my book gave (among many examples)

There is another reason why static methods are sometimes necessary. If a method manipulates a class that you do not own, you cannot add it to that class. Consider a method that computes the area of a rectangle. The Rectangle class in the standard library has no such feature, and we cannot modify that class. A static method solves this problem:

public class Geometry
{
  public static double area(Rectangle rect)
  {
    return rect.getWidth() * rect.getHeight();
  }
// More geometry methods can be added here.
}

Now we can tell you why the main method is static. When the program starts, there aren’t any objects. Therefore, the first method in the program must be a static method.

Ok, thats pretty cool, up until now I've just been really blindly putting public in front of all my methods, so this is great to know. But the review small problem on the next page caught my attention

The following method computes the average of an array list of numbers:

public static double average(ArrayList<Double> values)

Why must it be a static method?

Here I was like wait a sec. I'm pretty sure I did this without using static before. So I tried doing this again and pretty easily came up with the following

import java.util.ArrayList;
class ArrList
{
    private double sum;

    public ArrList()
    {
        sum = 0;
    }

    public double average(ArrayList <Double> values)
    {
        for(int i = 0; i < values.size() ; i++)
        {
            sum+=values.get(i);
        }

        return sum / values.size();

    }
}

public class Average
{
    public static void main(String [] args)
    {
        ArrList arrListObj = new ArrList();
        ArrayList<Double> testArrList = new ArrayList<Double>();
        testArrList.add(10.0);
        testArrList.add(50.0);
        testArrList.add(20.0);
        testArrList.add(20.0);
        System.out.println(arrListObj.average(testArrList));

    }
}

TLDR

Why does my book say that public static double average(ArrayList<Double> values) needs to be static?

ATTEMPT AT USING STATIC

public class Average
{
    public static void main(String [] args)
    {
        ArrayList<Double> testArrList = new ArrayList<Double>();
        ArrayList<Double> testArrListTwo = new ArrayList<Double>();
        testArrList.add(10.0);
        testArrList.add(50.0);
        testArrList.add(20.0);
        testArrList.add(20.0);
        testArrListTwo.add(20.0);
        testArrListTwo.add(20.0);
        testArrListTwo.add(20.0);
        System.out.println(ArrList.average(testArrList));
        System.out.println(ArrList.average(testArrListTwo)); // we don't get 20, we get 53.3333!


    }
}
Community
  • 1
  • 1
Muntasir Alam
  • 1,777
  • 2
  • 17
  • 26
  • You never really "need" `static`. But there's no real reason not to use it, since it avoids having to create an instance of `ArrList`. Plus, your implementation will break if you try to use the same `ArrList` instance to calculate multiple averages. – resueman Aug 11 '16 at 17:44
  • Need is kind of a strong word, [but I would argue it should be](http://stackoverflow.com/a/658422/3666763) – Kevin L Aug 11 '16 at 17:45
  • your ArrList example doesn't make sense. it has an instance variable that only gets initialized in the constructor, multiple calls to your method on the same instance will result in garbage. – Nathan Hughes Aug 11 '16 at 17:47
  • @NathanHughes, Could you expand? Not really sure what you mean sorry – Muntasir Alam Aug 11 '16 at 17:48
  • @cresjoy: Use your `average` method twice, with two different `ArrayList`s, and see what happens. – David Aug 11 '16 at 17:50
  • 3
    @cressjoy If you add a list (say `[10,15,20]`) to your object and compute the average, it'll correctly spit out 15. _using the same object_, if you add another list (say `[1,2,3]`), `arrListObject.average([1,2,3])` won't spit out 2 as expected because of the previous state - instead you'll get 17. – Kevin L Aug 11 '16 at 17:51
  • So how does static solve that problem @Kevin, I understand what you mean? – Muntasir Alam Aug 11 '16 at 17:54
  • 2
    @cresjoy: `static` doesn't *by itself* solve that problem. Removing the dependency of the state external to the method (the instance variable) solves the problem. Once there's no state external to the method, it's a potential candidate to be a `static` method if it semantically makes sense to make it such. – David Aug 11 '16 at 17:55
  • I see. I changed everything to static in my new edit, yet my new average is not what it should be, is it the same problem @Kevin was suggesting? – Muntasir Alam Aug 11 '16 at 18:02
  • are you still storing the sum as a static variable? the problem with your old implementation is that `sum` was never reset each time – Kevin L Aug 11 '16 at 18:04
  • @cresjoy: It sounds like you sprinkled in the `static` keyword and hoped for magic to happen, but didn't actually fix the problem of storing state outside of the method. – David Aug 11 '16 at 18:05
  • Yep I forgot to reset the sum to zero. But if I reset the sum to zero, and remove static the new average like you said is still messed up.!! Woah, did not expect that, now I finally get what you mean – Muntasir Alam Aug 11 '16 at 18:07
  • Is it safe to say that in this case, static is more or less a matter of technique and good coding practise, rather than the actual function of the code static and what not itself? – Muntasir Alam Aug 11 '16 at 18:13

3 Answers3

1
  1. If it is not static, then any other class that wants to use this method must first create an instance of this object.

From some other class:

Average.average(new ArrayList<Double>()); // legal only if static
new Average().average(new ArrayList<Double>()); // necessary if not static
// and only makes sense if Average can be instantiated in the first place
  1. It's legal to make it an instance (i.e. not static) variable, but the method is actually harder to understand. If it is static then whoever reads the code knows it does not use any member variables of the class.

    // In the class body
    int x = 0; // member variable
    public static double average() {
        x = x + 1; // illegal
    }
    

The less something can do, the easier to understand what it does do.

djechlin
  • 59,258
  • 35
  • 162
  • 290
  • It looks like the past i've made everything public since I really didn't know what static did. It looks like everything is better being static. Should I just put static on most methods then? It seems "easier" – Muntasir Alam Aug 12 '16 at 00:44
1

It doesn't.

The only method which needs to be static is the initial main() method. Anything and everything else is up to you as the programmer to decide what makes sense in your design.

static has nothing to do with public accessors (as you allude to), and it has nothing to do with the technical operation being performed. It has everything to do with the semantics of the operation and the class which holds it.

An instance (non-static) method exists on a particular instance of a class. Semantically it should perform operations related to that specific instance. A static method exists on a class in general and is more conceptual. It doesn't do anything to a particular instance (unless it's provided an instance of something as a method argument of course).

So you really just need to ask yourself about the semantics of the operation. Should you need new instance of an object to perform an operation? Or should the operation be available without an instance? That depends on the operation, on what the objects represent, etc.

David
  • 208,112
  • 36
  • 198
  • 279
  • I suppose my textbook meant "why is it strongly reccomended that this method is static" judging by the answers. I don't really understand, in the first example we made it static because the Rectangle library does not have an area feature. Is it the same idea here? We make it static since there is no built in average method? – Muntasir Alam Aug 11 '16 at 17:53
  • @cresjoy: It seems to be the same conceptual reason, yes. There are lots of ways these operations can be organized, not just `static` vs. instance. – David Aug 11 '16 at 17:54
  • Hmm, I feel like all the exercises I have been doing now involve performing some operation on arraylists ( like getting the sum, then doing something etc etc), does that mean i should have made all my methods static from before? – Muntasir Alam Aug 11 '16 at 17:56
  • @cresjoy: I don't know, maybe? The best answer to that is, "If it makes sense, then yes." There's no universal rule for when something should be `static`. The semantics of what you're building can be very subjective. It *might* make sense to have a bunch of `static` methods. It *might* make sense to have an object of some kind which carries instance-level state and performs operations. Etc. – David Aug 11 '16 at 17:59
  • Ok. This stuff sure seems rather verbose and complex :/ Thanks – Muntasir Alam Aug 11 '16 at 18:02
1

Static methods like the area, average are usually utility functions. You don't need any object to use an utility function. For example consider Math.pow you don't need to instantiate any object to use the power function, just use Math.pow(10.0, 2.0) to get (10.0)^2

In short : Static method means class method, that is no instance of that object is needed to invoke. whereas your average method is an instance method, you need an object to invoke that method.

SomeDude
  • 13,876
  • 5
  • 21
  • 44