Properties and property bindings introduced in Java 8 are extremely useful programming concepts. They are especially useful when you are developing user interfaces. In fact they are so useful that developers have fallen victim to the idea that everything should be a property instead of a primitive. Unfortunately they easily forget that properties such as SimpleLongProperty are much bigger objects than standard types such as Long. And of course they are much bigger than primitive data types such as long.
In one of my current projects pretty much every model object used by the client is composed of properties. For many of these model objects it is the right approach because they will be edited / modified via JavaFX controls. But there are also many model objects that are not edited. They exist to support the rendering of schedules in the FlexGanttFX control. These objects do not need to be observed, hence they do not need to provide properties … but they do and they waste a lot of memory because they do.
One way to fix this would be to refactor the model classes and to get rid of all properties, but then again we might want to use these objects in a future release in a different context and then we might need properties because we want to edit them directly. What to do?
Shadow Fields
The solution to this problem is something I recently saw Gerrit Grunwald do in the code of his Medusa project and a pattern that was described by Mr. Properties himself Michael Heinrichs. The pattern makes use of a “shadow field” that is of the same type as the wrapped object inside the property. When using this pattern a property will only be created when it is really needed (“when somebody asks for it”).
Example
In this example we want to manage an attribute called “title”. We need a setter, a getter, and the property accessor.
private String _title = "Untitled"; // shadow field
private StringProperty title;
public final String getTitle() {
return title == null ? _title : title.get();
}
public final void setTitle(String newTitle) {
if (title == null) {
_title = newTitle;
} else {
title.set(newTitle);
}
}
public final StringProperty titleProperty() {
if (title == null) {
/// !!!! pass shadow field to constructor
title = new SimpleStringProperty(this, "title", _title);
/// !!!! clear shadow reference
_title = null;
} return title; }
By using this pattern I was able to bring down the memory footprint from 310 MB to 250 MB for a specific use case in my project. The saved memory is ten times the total memory my computer had when I was a student. Just think about that!
Obviously this means even more boilerplate code for properties. It would be great if the IDE plugins would support the shadow field strategy, too. For Eclipse I have already submitted an enhancement ticket, so I hope Tom Schindl will look at it 🙂
Yes. That was my first reservation; loads of boilerplate code. And even if the EDI will generate this, it will still greatly impact the source code. We (Java) really need to find a better way.
Yes, direct language support would be sweet.
Direct language support would be great. But then I would love to be able to access a property path instead of just the property of a given instance.
In my application I generate static innerclasses and some bytecode-magic, allowing me to access properties like this:
property = PickupRequestController.p.pickupRequest.pickupAddress.address1
String address1 = property.get(controllerInstance)
Such things would be much more valuable than the var or val keywords… 🙂
I use a little bit another way, introduce only one simple Property, all others come as Bindings by request, for example:
private String title;
private final BooleanProperty isChanged = new SimpleBooleanProperty();
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = Objects.requireNotNull(title);
fireChanged();
}
public StringProperty createTitleBinding() {
return Bindings.createStringBinding(this::getTitle, isChanged);
}
private void fireChanged() {
isChanged.set(!isChanged.get());
}
@Dmitry This looks like it does not save a whole lot of memory (which is the idea behind the shadow fields). You still have one full property for each attribute. And just because it is a BoolenProperty does not mean it is tiny.
I haven’t looked at Lombok in awhile, but it wonder if an annotation could be created to apply the boilerplate code.
-Carl
Dirk,
Should the setTitle() method’s else statement call titleProperty().set(title) instead of title.set(title)
?
Npe would occur I believe.
Thanks for the tip!
Carl
@carldea …. no, this looks ok. I am already checking if title is not null, so no NPE.
Lombok (or at least a custom annotation) will work. I have not used lombok myself, somehow I keep steering away from it, but people who did felt it to be more of a kludge compared to used an extended language like Groovy or Xtend (especially in IDE support).
Dirk,
My mistake!
Whoops it was late night for me. I see title is checked first. I thought title was _title. I’m used to properties having a suffix xyzProperties.
Very cool trick.
I see now the bean can be use without properties ever created. But as soon as u use titleProperty() one gets created.
Thanks for the tip!
Carl
Dirk,
Not to be nit-picky, but I think some lines didn’t compile.
public final String getTitle() {
title == null ? return _title : title.get();
}
should be:
public final String getTitle() {
return title == null ? _title : title.get(); // <--- change } Also, public final StringProperty titleProperty() { if (title == null) { /// !!!! pass shadow field to constructor title = new StringProperty(this, "title", _title); } return title; } Should be: public final StringProperty titleProperty() { if (title == null) { /// !!!! pass shadow field to constructor title = new SimpleStringProperty(this, "title", _title); //<-- change } return title; } It's 11:16pm If i'm incorrect I'm probably coding in another language 😉
@carldea that’s right, I wrote it directly into the blog. I am lost without an IDE 🙂 But I guess the basic message came across.
It is fixed now.
[…] using an interesting pattern called Shadow Fields. To see his post please visit his blog entry JavaFX Tip 23: Save Memory! Shadow Fields for Properties.. Dirk’s JavaFX tip does help solve the problem mentioned above (lessening the heap), however […]
[…] JavaFX Tip 23: Save Memory! Shadow Fields for Properties. […]
[…] let me quickly mention how we got to this point. For starters, Dirk created a JavaFX tip 23: “Save Memory Shadow Fields for Properties” to help application developers save memory when using JavaFX Properties. Pretty impressive […]
[…] pattern called Shadow Fields. To see his post, please visit his blog entry JavaFX Tip 23: Save Memory! Shadow Fields for Properties. Dirk’s JavaFX tip does help solve the problem mentioned above (lessening the heap); however, […]
[…] taking turns trying to come up with patterns to minimise the cost of properties. I linked to Dirks original post last week, but then Carl followed this up, followed by Dirk, then followed twice by […]
[…] taking turns trying to come up with patterns to minimise the cost of properties. I linked to Dirks original post last week, but then Carl followed this up, followed by Dirk, then followed twice by […]