Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Differentiating State and Dependency Fields in Java

DZone's Guide to

Differentiating State and Dependency Fields in Java

Wondering about the optimal visuals for differentiating state and dependency fields in a Java class? Check out this sweet tutorial which breaks down statefulness and dependencies.

· Java Zone
Free Resource

Build vs Buy a Data Quality Solution: Which is Best for You? Gain insights on a hybrid approach. Download white paper now!

A recent DZone article reminded me of a question I've been privately grappling with:

What is the best way to visually differentiate state fields from dependency fields within a Java class?

This may lead you to grapple with a question of your own: Why would you care?

Well, if you're maintaining an existing code base, you want to be able to get up to speed quickly. To do that, you'll need to read code. Conventionally, fields are placed at the top of a class, so they're one of the first things you notice when reading code. The more information you can learn from looking at the fields alone, the more quickly the class can be understood.

Two useful pieces of information fields can convey are:

  1. Statefulness - How much state does this class maintain? (internally-managed objects)
  2. Dependencies - What things must we provide this class in order for it to function? (externally-managed objects)

Unfortunately, Java does not provide a straightforward way to indicate which fields are for which purpose. To illustrate, here's a conventionally structured Java class containing both state and dependency fields:

public class Radio {
    private int volumeLevel;
    private float station;
    private Set<Float> presets;
    private Antenna antenna;
    private PowerSupply powerSupply;

    // constructors, accessors, and other methods
}

Someone with a general understanding of radios may surmise that the first three fields are the radio's state and the latter two are its dependencies.

But is there a convention we could apply that would make the distinction more explict and eliminate the need to guess? The rest of this article explores some ideas.

Comments

One obvious approach would be use comments.

public class Radio {
    // state
    private int volumeLevel;
    private float station;
    private Set<Float> presets;

    // dependencies
    private Antenna antenna;
    private PowerSupply powerSupply;
}

Pros: Simple, and doesn't break standard formatting conventions.

Cons: Visual effectiveness declines when there are field-level JavaDocs, multiline block comments, or annotations. You could also indicate the kind within the field-level JavaDocs themselves, but you probably do not want to write one for each field.

Structural Separation Within Class

Another approach would be to separate the field groups within the class, such as putting dependency fields at the top of the class and state fields beneath the constructors, at the bottom of the file, or interspersed between getter/setters.

public class Radio {
    private Antenna antenna;
    private PowerSupply powerSupply;

    public Radio(Antenna antenna, PowerSupply powerSupply) { ... }

    private int volumeLevel;
    public int getVolumeLevel() { ... }
    public void setVolumeLeve(int volumeLeve) { ... }

    private float station;
    public float getStation() { ... }
    public void tuneStation(float amount) { .. }

    private Set<Float> presets = new HashSet<>();
    public void addPreset(float station) { ... }
    public void removePreset(float station) { ... }

    // other methods
}

Pros: Works with any combination of field modifiers, annotations, and field-level JavaDocs.

Cons: Self-defeating in that it forces reader to look at more than just the top of the class to locate state information. Breaks formatting conventions.

Hungarian Notation

Repeating type information in names is wholly unnecessary in a language like Java, but Hungarian Notation can be used to indicate other information, such as intended use as a dependency field.

public class Radio {
    private int volumeLevel;
    private float station;
    private Set<Float> presets;

    private Antenna antennaDependency;
    private PowerSupply powerSupplyDependency;
}

Pros: Works with any combination of field modifiers, annotations, and field-level JavaDocs.

Cons: Makes names longer; if you want to have getter/setter method names without the word "dependency" then you'll have to manually code them.

Marking Dependencies as Final

If you're a fan of constructor-based injection, dependency fields can (and should) be declared as final. In contrast, state fields are commonly mutable and would not be marked as final.

public class Radio {
    private int volumeLevel;
    private float station;
    private Set<Float> presets = new HashSet<>();

    private final Antenna antenna;
    private final PowerSupply powerSupply;
}

Pros: A good practice.

Cons: State fields that are initialized to mutable objects (such as an empty collection) should also receive a final modifier, making the state field indistinguishable from a dependency field. When using setter-based injection, dependencies cannot always be marked as final.

IoC Field Injection Annotations

If you're using Spring, CDI, or some other IoC framework, you might be applying field-injection annotations on dependency fields but not on state fields. The presence of these annotations may be sufficient to visually distinguish fields.

@Component
public class Radio {
    private int volumeLevel;
    private float station;
    private final Set<Float> presets = new HashSet<>();

    @Autowired
    private Antenna antenna;
    @Autowired
    private PowerSupply powerSupply;
}

Pros: Convenient if already using an IoC framework.

Cons: Would only work on classes managed by the IoC framework. Requires use of field injection, which is inferior to constructor injection. State fields may be annotated in certain circumstances, making the distinction less obvious, e.g.

@Value("${default.volume.level}")
private int volumeLevel;

Custom Documentation Annotations

We can create our own annotations to differentiate the kinds of fields.

public class Radio {
    @State
    private int volumeLevel;
    @State
    private float station;
    @State
    private final Set<Float> presets = new HashSet<>();

    @Dependency
    private Antenna antenna;
    @Dependency
    private PowerSupply powerSupply;
}

Pros: Visually effective. Works with any combination of field modifiers and field-level JavaDocs.

Cons: If there are multiple annotations on the fields, the distinction becomes less obvious.

Lombok Annotations for State Fields

Lombok provides annotations that turn fields into full-fledged properties. These presence of these annotations can be used on state fields exclusively to distinguish them from dependency fields.

public class Radio {
    @Getter @Setter
    private int volumeLevel;
    @Getter @Setter
    private float station;
    @Getter
    private final Set<Float> presets = new HashSet<>();

    private Antenna antenna;
    private PowerSupply powerSupply;
}

Pros Convenient if already using Lombok.

Cons Ineffective when @Data annotation is used or if dependency fields need getters and setters, too. Not all state fields may need getters and/or setters. For example, the radio API could restrict the underlying volume field to only being mutated through these methods:

public void increaseVolume() { ... }
public void decreaseVolume() { ... }

Dependencies in an Abstract Parent Class

Dependency fields could be moved exclusively to an abstract parent class.

// BaseRadio.java
public abstract class BaseRadio {
    protected Antenna antenna;
    protected PowerSupply powerSupply;
}

// Radio.java
public class Radio extends BaseRadio {
    private int volumeLevel;
    private float station;
    private final Set<Float> presets = new HashSet<>();
}

Pros: Effective in separating the state fields from dependency fields, but...

Cons: Self-defeating in that you have to read two files now. Boilerplate-y. May interfere with existing class hierarchies; inheritance isn't as nice as composition. Dependency fields are exposed to the entire package.

Dependencies Holder Inner Class

Instead of throwing dependencies into a base class, you can put them into a private inner class.

public class Radio {    
    private int volumeLevel;
    private float station;
    private final Set<Float> presets = new HashSet<>();

    private final Dependencies dependencies = new Dependencies();
    private class Dependencies {
        Antenna antenna;
        PowerSupply powerSupply;
    }

    public Radio(Antenna antenna, PowerSupply powerSupply) {
        dependencies.antenna = antenna;
        dependencies.powerSupply = powerSupply;
    }
}

Pros: The distinction is explicit given the dependency fields are in their own scope.

Cons: The word "dependencies" appears so many times! Boilerplate-y. You lose some IDE/compiler help, like enforcement offinal and constructor generation with the dependency types as arguments.

Dependencies Holder Private Top-Level Class

Instead of an inner class, you can move dependencies to a private top-level class.

// Radio.java
public class Radio {
    private int volumeLevel;
    private float station;
    private final Set<Float> presets = new HashSet<>();
    private final Dependencies dependencies;

    public Radio(Antenna antenna, PowerSupply powerSupply) {
        dependencies = new Dependencies(antenna, powerSupply);
    }
}

class Dependencies {
    final Antenna antenna;
    final PowerSupply powerSupply;

    public Dependencies(Antenna antenna, PowerSupply powerSupply) {
        this.antenna = antenna;
        this.powerSupply = powerSupply;
    }
}

Pros: Same as the inner class holder.

Cons: Same as the inner class holder, but more self-defeating since the dependency fields get pushed to the bottom of the file.

State in a Single Map

Why bother with individual state fields at all? We could put all state into a single Map!

public class Radio {
    private enum StateProperty {
        VOLUME_LEVEL, STATION, PRESETS
    }
    private final Map<StateProperty, Object> state = new EnumMap<>(StateProperty.class);

    private final Antenna antenna;
    private final PowerSupply powerSupply;
}

Pros: Should sufficiently discourage class writers from making their classes stateful.

Cons: Getters and setters become more complicated to write. Performance impact due to introduction of Map instance, etc. etc.

*   *   *   *   *

I like elements of the Hungarian notation, custom annotations, and (strangely) the top-level private holder class. But overall, I don't feel there's any one approach I'd be willing to adopt as a convention.

To maximize readability, I suggestion sticking to existing best practices (e.g. constructor injection, composition over inheritance, marking fields as final) and, most importantly, keeping class size small.

Build vs Buy a Data Quality Solution: Which is Best for You? Maintaining high quality data is essential for operational efficiency, meaningful analytics and good long-term customer relationships. But, when dealing with multiple sources of data, data quality becomes complex, so you need to know when you should build a custom data quality tools effort over canned solutions. Download our whitepaper for more insights into a hybrid approach.

Topics:
java ,state ,dependencies

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}