views:

24809

answers:

15

Is it completely against the Java way to create struct like objects?

class SomeData1 {
    public int x;
    public int y;
}

I can see a class with accessors and mutators being more Java like.

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

The class from the first example is notationally convenient.

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}

This is not as convenient.

// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}
A: 

I don't see the harm if you know that it's always going to be a simple struct and that you're never going to want to attach behaviour to it.

John Topley
+1  A: 

If the Java way is the OO way, then yes, creating a class with public fields breaks the principles around information hiding which say that an object should manage its own internal state. (So as I'm not just spouting jargon at you, a benefit of information hiding is that the internal workings of a class are hidden behind an interface - say you wanted to change the mechanism by which your struct class saved one of its fields, you'll probably need to go back and change any classes that use the class...)

You also can't take advantage of the support for JavaBean naming compliant classes, which will hurt if you decide to, say, use the class in a JavaServer Page which is written using Expression Language.

The JavaWorld article Why Getter and Setter Methods are Evil article also might be of interest to you in thinking about when not to implement accessor and mutator methods.

If you're writing a small solution and want to minimise the amount of code involved, the Java way may not be the right way - I guess it always depends on you and the problem you're trying to solve.

Brabster
+10  A: 

This is often picked up topic. The drawback of creating public fields in objects is that you have no control over values that are set to it. And sometimes it's better to return a copy of field's object or transform it somehow etc. You can mock such methods in your tests. If you create new class you might not see all possible actions. It's like defensive programming - someday getters and setters may be helpful and it doesn't cost a lot to create/use them. So they are sometimes useful.

In practice most fields have simple getters and setters. That's why in Java 7 probably there will be added properties which would behave like normal fields unless you need more control over getting/setting a value to them. There's still discussion over it. One of possible solutions would look like this:

public property String foo;   
a->Foo = b->Foo;

You can read more on this on Alex Miller's Java 7 page.

Update: It's highly unlikely that property support will be added in Java 7 or perhaps ever. Other JVM languages like Groovy, Scala, etc do support this feature now. - Alex Miller

bibix
+1  A: 

This is a question on Object Oriented Design, not Java the language. It's generally good practice to hide data types within the class and expose only the methods that are part of the class API. If you expose internal data types, you can never change them in the future. If you hide them, your only obligation to the user is the method's return and argument types.

Jonathan
+3  A: 

By the way, the structure you're giving as an example already exist in the Java base class library as java.awt.Point. It has x and y as public fields, check it out for yourself.

If you know what you're doing, and others in your team know about it, then it is okay to have public fields. But you shouldn't rely on it because they can cause headaches as in bugs related to developers using objects as if they were stack allocated structs (java objects are always sent to methods as references and not as copies).

Spoike
+20  A: 

Use common sense really. If you have something like

public class ScreenCoord2D
{
    public int x;
    public int y;
}

Then there's little point in wrapping them up in getters and setters. You're never going to store an x,y coordinate in whole pixels any other way. Getters and setters will only slow you down.

On the other hand, with

public class BankAccount
{
    public int balance;
}

you might want to change the way a balance is calculated at some point in the future. This should really use getters and setters.

It's always preferable to know why you're applying good practice, so that you know when it's ok to bend the rules.

izb
+4  A: 

Re: aku, izb, John Topley...

Watch out for mutability issues...

It may seem sensible to omit getters/setters. It actually may be ok in some cases. The real problem with the proposed pattern shown here is mutability.

The problem is once you pass an object reference out containing non-final, public fields. Anything else with that reference is free to modify those fields. You no longer have any control over the state of that object. (Think what would happen if Strings were mutable.)

It gets bad when that object is an important part of the internal state of another, you've just exposed internal implementation. To prevent this, a copy of the object must be returned instead. This works, but can cause massive GC pressure from tons of single-use copies created.

If you have public fields, consider making the class read-only. Add the fields as parameters to the constructor, and mark the fields final. Otherwise make sure you're not exposing internal state, and if you need to construct new instances for a return value, make sure it won't be called excessively.

See: "Effective Java" by Joshua Bloch -- Item #13: Favor Immutability.

PS: Also keep in mind, all JVMs these days will optimize away the getMethod if possible, resulting in just a single field-read instruction.

Mark Renouf
How does a getter/setter resolve this issue. You still have a reference, you don't have any synchronization with the operations. Getters/setters don't provide protection in and of themselves.
he_the_great
+4  A: 

To address mutability concerns you can declare x and y as final. For example:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

Calling code that attempts to write to these fields will get a compile time error of "field x is declared final; cannot be assigned".

The client code can then have the 'short-hand' convenience you described in your post

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}
Brian
+1  A: 

The problem with using public field access is the same problem as using new instead of a factory method - if you change your mind later, all existing callers are broken. So, from an API evolution point of view, it's usually a good idea to bite the bullet and use getters/setters.

One place where I go the other way is when you strongly control access to the class, for example in an inner static class used as an internal data structure. In this case, it might be much clearer to use field access.

By the way, on e-bartek's assertion, it is highly unlikely IMO that property support will be added in Java 7.

Alex Miller
This is true, but if you're using Java it's not a concern, since you can refactor an entire code-base in one click (Eclipse, Netbeans, probably VIM and Emacs too). If you've opted for one of its dynamic friends, like Groovy, even a simple encapsulation could have you fixing for hours or days. Luckily you'd have your test cases which would inform you... how much more code you have to fix.
Yar
You assume of course that all of the users are *in your code base* but of course, that's often not true. Often it's not even possible for various non-technical reasons to change code that might be in your own code base.
Alex Miller
+1  A: 

I frequently use this pattern when building private inner classes to simplify my code, but I would not recommend exposing such objects in a public API. In general, the more frequently you can make objects in your public API immutable the better, and it is not possible to construct your 'struct-like' object in an immutable fashion.

As an aside, even if I were writing this object as a private inner class I would still provide a constructor to simplify the code to initialize the object. Having to have 3 lines of code to get a usable object when one will do is just messy.

Kris Nuttycombe
A: 

You can make a simple class with public fields and no methods in Java, but it is still a class and is still handled syntactically and in terms of memory allocation just like a class. There is no way to genuinely reproduce structs in Java.

cblades
A: 

Sometime I use such class, when I need to return multiple values from a method. Of course, such object is short lived and with very limited visibility, so it should be OK.

PhiLho
A: 

I have tried this in a few projects, on the theory that getters and setters clutter up the code with semantically meaningless cruft, and that other languages seem to do just fine with convention-based data-hiding or partitioning of responsibilities (e.g. python).

As others have noted above, there are 2 problems that you run into, and they're not really fixable:

  • Just about any automated tool in the java world relies on the getter/setter convention. Ditto for, as noted by others, jsp tags, spring configuration, eclipse tools, etc. etc... Fighting against what your tools expect to see is a recipe for long sessions trolling through google trying to find that non-standard way of initiating spring beans. Really not worth the trouble.
  • Once you have your elegantly coded application with hundreds of public variables you will likely find at least one situation where they're insufficient- where you absolutely need immutability, or you need to trigger some event when the variable gets set, or you want to throw an exception on a variable change because it sets an object state to something unpleasant. You're then stuck with the unenviable choices between cluttering up your code with some special method everywhere the variable is directly referenced, having some special access form for 3 out of the 1000 variables in your application.

And this is in the best case scenario of working entirely in a self-contained private project. Once you export the whole thing to a publicly accessible library these problems will become even larger.

Java is very verbose, and this is a tempting thing to do. Don't do it.

Steve B.
A: 

There is nothing wrong with that type of code, provided that the author knows they are structs (or data shuttles) instead of objects. Lots of Java developers can't tell the difference between a well-formed object (not just a subclass of java.lang.Object, but a true object in a specific domain) and a pineapple. Ergo,they end up writing structs when they need objects and viceversa.

luis.espinal
A: 

As with most things, there's the general rule and then there are specific circumstances. If you are doing a closed, captured application so that you know how a given object is going to be used, then you can exercise more freedom to favor visibility and/or efficiency. If you're developing a class which is going to be used publicly by others beyond your control, then lean towards the getter/setter model. As with all things, just use common sense. It's often ok to do an initial round with publics and then change them to getter/setters later.

EvanR