77

I have a class that consists only of static member variables and static methods. Essentially, it is serving as a general-purpose utility class.

Is it bad practice for a class to contain only static member variables and static methods?

Stephen Watkins
  • 25,047
  • 15
  • 66
  • 100
  • 29
    `java.lang.Math` is 100% static methods with a `private` constructor (can't be instantiated). – Asaph Dec 21 '09 at 22:01
  • Not sure whether this question has been asked in this forum. But is it a bad practice for a class to have only static fields? I have seen a lot of such classes and in my opinion they don't fit in OOP. – ka3ak Sep 24 '12 at 13:29
  • @ka3ak Classes only having static fields is partially addressed in a few answers to this question. – Stephen Watkins Sep 24 '12 at 16:44

15 Answers15

91

No, I don't think so at all. It is worse practice to have a class full of instance methods which don't actually depend on a particular instance. Making them static tells the user exactly how they are intended to be used. Additionally, you avoid unnecessary instantiations this way.

EDIT: As an afterthought, in general I think its nice to avoid using language features "just because", or because you think that that is the "Java way to do it". I recall my first job where I had a class full of static utility methods and one of the senior programmers told me that I wasn't fully harnessing the OO power of Java by making all of my methods "global". She was not on the team 6 months later.

danben
  • 80,905
  • 18
  • 123
  • 145
20

As long as the class has no internal state and is essentially what is known as a leaf class (utility classes fall into this category), in other words it is independent of other classes. It is fine.

The Math class being a prime example.

Finglas
  • 15,518
  • 10
  • 56
  • 89
14

Sounds reasonable.

Note: Classes that do this often have a private no-arg constructor just so that the compiler yields an error if a programmer tries to create an instance of the static class.

Jason S
  • 184,598
  • 164
  • 608
  • 970
  • 5
    A private default constructor also prevents sub-classing your static class. – David Dec 21 '09 at 22:02
  • 1
    is there any reason you would want to sub-class a static class? (can't think of one... I'm not a language guru) – Jason S Dec 21 '09 at 22:29
  • 4
    Preventing sub-classing in this case is a "pro". It is possible someone else working on your project could accidentally try and sub-class your static class (through a typo, or misunderstanding). By adding a private default constructor you are adding more meaning to your class by more strictly enforcing how it can be used. – David Dec 21 '09 at 22:53
  • 1
    Making the class final would also prevent sub-classing. – HexAndBugs Jan 09 '13 at 14:06
10

Static methods don't worry me much (except for testing).

In general, static members are a concern. For example, what if your app is clustered? What about start-up time -- what kind of initialization is taking place? For a consideration of these issues and more, check out this article by Gilad Bracha.

Michael Easter
  • 23,733
  • 7
  • 76
  • 107
3

It's perfectly reasonable. In fact, in C# you can define a class with the static keyword specifically for this purpose.

Taylor Leese
  • 51,004
  • 28
  • 112
  • 141
3

Just don't get carried away with it. Notice that the java.lang.Math class is only about math functions. You might also have a StringUtilities class which contains common string-handling functions which aren't in the standard API, for example. But if your class is named Utilities, for example, that's a hint that you might want to split it up.

Paul Clapham
  • 1,074
  • 5
  • 6
2

Note also that Java specifically introduced the static import: (http://en.wikipedia.org/wiki/Static_import)

Static import is a feature introduced in the Java programming language that members (fields and methods) defined in a class as public static to be used in Java code without specifying the class in which the field is defined. This feature was introduced into the language in version 5.0.

The feature provides a typesafe mechanism to include constants into code without having to reference the class that originally defined the field. It also helps to deprecate the practice of creating a constant interface: an interface that only defines constants then writing a class implementing that interface, which is considered an inappropriate use of interfaces[1].

The mechanism can be used to reference individual members of a class:

 import static java.lang.Math.PI;
 import static java.lang.Math.pow;

or all the static members of a class:

 import static java.lang.Math.*;
peter.murray.rust
  • 37,407
  • 44
  • 153
  • 217
  • I think this is a little off-topic for what he is asking. Static import has nothing to do with whether a class ONLY has static members; it works if there are any. – danben Dec 21 '09 at 22:09
  • 1
    Both good info and a great argument for why this is something we are meant to do. – Chuck Dec 21 '09 at 22:11
  • Sorry, I disagree - I think its an argument for having static methods, but it says nothing of having classes that are not meant to be instantiated. – danben Dec 21 '09 at 22:12
  • @danben: Static imports make less sense (at least to me) on a class you are going to instantiate. It makes the most sense on "utility classes" that hold lots of static methods like java.lang.Math. Do you not think so? – Chuck Dec 21 '09 at 22:21
  • Might be nitpicking here, but I agree with you when you say they make less sense on a class you are going to instantiate; however, I don't agree that they make more sense on a class that can't be instantiated. – danben Dec 21 '09 at 22:30
  • I'm not sure if I said that clearly, but what I meant by that is that there is no reason not to use a static import for a static method on a class that can otherwise be instantiated. – danben Dec 21 '09 at 22:32
2

While I agree with the sentiment that it sounds like a reasonable solution (as others have already stated), one thing you may want to consider is, from a design standpoint, why do you have a class just for "utility" purposes. Are those functionals truly general across the entire system, or are they really related to some specific class of objects within your architecture.

As long as you have thought about that, I see no problem with your solution.

JasCav
  • 34,458
  • 20
  • 113
  • 170
1

The Collections class in Java SDK has static members only.

So, there you go, as long as you have proper justification -- its not a bad design

Mihir Mathuria
  • 6,479
  • 1
  • 22
  • 15
1

Utility methods are often placed in classes with only static methods (like StringUtils.) Global constants are also placed in their own class so that they can be imported by the rest of the code (public final static attributes.)

Both uses are quite common and have private default constructors to prevent them from being instantiated. Declaring the class final prevents the mistake of trying to override static methods.

If by static member variables you did not mean global constants, you might want to place the methods accessing those variables in a class of their own. In that case, could you eleborate on what those variables do in your code?

rsp
  • 23,135
  • 6
  • 55
  • 69
1

This is typically how utility classes are designed and there is nothing wrong about it. Famous examples include o.a.c.l.StringUtils, o.a.c.d.DbUtils, o.s.w.b.ServletRequestUtils, etc.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
1

According to a rigid interpretation of Object Oriented Design, a utility class is something to be avoided.

The problem is that if you follow a rigid interpretation then you would need to force your class into some sort object in order to accomplish many things.

Even the Java designers make utility classes (java.lang.Math comes to mind)

Your options are:

double distance = Math.sqrt(x*x + y*y);  //using static utility class

vs:

RootCalculator mySquareRooter = new SquareRootCalculator();
mySquareRooter.setValueToRoot(x*x + y*y);
double distance;
try{
   distance = mySquareRooter.getRoot();
}
catch InvalidParameterException ......yadda yadda yadda.      

Even if we were to avoid the verbose method, we could still end up with:

Mathemetician myMathD00d = new Mathemetician()
double distance = myMathD00d.sqrt(...);

in this instance, .sqrt() is still static, so what would the point be in creating the object in the first place?

The answer is, create utility classes when your other option would be to create some sort of artificial "Worker" class that has no or little use for instance variables.

Chris Cudmore
  • 29,793
  • 12
  • 57
  • 94
1

This link http://java.dzone.com/articles/why-static-bad-and-how-avoid seems to go against most of the answers here. Even if it contains no member variables (i.e. no state), a static class can still be a bad idea because it cannot be mocked or extended (subclassed), so it is defeating some of the principles of OO

Andy
  • 10,412
  • 13
  • 70
  • 95
0

I wouldn't be concerned over a utility class containing static methods.

However, static members are essentially global data and should be avoided. They may be acceptable if they are used for caching results of the static methods and such, but if they are used as "real" data that may lead to all kinds of problems, such as hidden dependencies and difficulties to set up tests.

starblue
  • 55,348
  • 14
  • 97
  • 151
0

From TSLint’s docs:

Users who come from a Java-style OO language may wrap their utility functions in an extra class, instead of putting them at the top level.

The best way is to use a constant, like this:

export const Util = {
    print (data: string): void {
        console.log(data)
    }
}

Examples of incorrect code for this rule:

class EmptyClass {}

class ConstructorOnly {
  constructor() {
    foo();
  }
}

// Use an object instead:
class StaticOnly {
  static version = 42;
  static hello() {
    console.log('Hello, world!');
  }
}

Examples of correct code for this rule:

class EmptyClass extends SuperClass {}

class ParameterProperties {
  constructor(public name: string) {}
}

const StaticOnly = {
  version: 42,
  hello() {
    console.log('Hello, world!');
  },
};
Matheus Toniolli
  • 438
  • 1
  • 7
  • 16