0

I have a java-8 class:

  class MyClass{
    double field1;
    double field2;
    int field3;
    ...
    float fieldN;

    boolean isEmpty() {
        // I want to implement this such that if all my numeric fields are 0's then return true else false
    }

}

What would be the most elegant way of implementing isEmpty() instead of adding many different if(fieldX == 0 ) conditions in there ?

Javadee
  • 139
  • 10
  • who says that list of fieldX == 0 is not the best way to solve this? – Stultuske Aug 28 '18 at 11:03
  • 1
    And please note the semantics: what if 0 is a legit value for some of the field(s). These are primitives, they can't be *empty*. They are zero, or maybe NaN, but not empty or null. – GhostCat Aug 28 '18 at 11:20
  • 1
    I see nothing unelegant about the straightforward `return field1 == 0 && field2 == 0 && field3 = 0 && … && fieldN == 0;`. – Ole V.V. Aug 28 '18 at 11:24
  • Checking equality of float/double values and "zero" is considered a bad practice – Nikolai Shevchenko Aug 28 '18 at 11:47
  • Interesting, @NikolayShevchenko. Why? What do you suggest instead? Have you got a source? I know that comparing `float` and `double` for equality is generally dangerous, but I considered comparison to 0 safe, at least if, as I suppose here, the 0 comes from the field not having been initialized. – Ole V.V. Aug 28 '18 at 14:40
  • [Is it ok to compare floating points to 0.0 without epsilon?](https://stackoverflow.com/questions/39108471/is-it-ok-to-compare-floating-points-to-0-0-without-epsilon) (it’s a C++ question, but I would presume the answers are valid in Java too; Java does follow the IEEE standard mentioned in a couple of the answers). Also @NikolayShevchenko – Ole V.V. Aug 29 '18 at 11:01

4 Answers4

2

YMMV about whether you find it "elegant", but you can use a DoubleStream:

boolean isEmpty() {
    return DoubleStream.of(field1, field2, field3)
        .allMatch(f -> f == 0);
}
daniu
  • 14,137
  • 4
  • 32
  • 53
2

if you don't want to declare each field and if else you can use reflection and stream filter

public boolean isEmpty()  throws IllegalAccessException {
    Field[] valueObjFields = this.getClass().getDeclaredFields();

    Object _this=this;
    return Arrays.stream(valueObjFields).allMatch(o -> {
        try {
            return Double.parseDouble(o.get(_this).toString())== 0;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    });
}

this method returns true if all fields are empty and you dont have to check each field separately.

Even if you add more fields in class this method will work without chenging.

Rupesh Agrawal
  • 645
  • 8
  • 22
Manasi
  • 765
  • 6
  • 17
1

The most elegant way would be using JSR 380 bean validation.

It is a set of tools, including useful common annotations, to define bean class metadata for constraint validation.

You don't need to read the full spec to get the gist of it :

You'd want to define a group class for this specific set of constraints

public interface MyCustomIsEmpty{}

Then annotate each relevant field with

@Max(value = 0, groups = { MyCustomIsEmpty.class })
@Min(value = 0, groups = { MyCustomIsEmpty.class })

making sure to use the javax.validation.constraints annotation classes.

Now your actual isEmpty() would be as simple as getting the default validator and validating the current instance :

public boolean isEmpty() {
    // Gets validator instance from factory
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    validator = factory.getValidator();    

    // Validates 'this' using only fields belonging to the MyCustomIsEmpty group
    Set<ConstraintViolation<MyClass>> constraintViolations = validator.validate(this, MyCustomIsEmpty.class);

    // there are lots of fancy things you could do but this covers your case 
    return constraintViolations.isEmpty();
}

You could simplify the equivalent of the two combined annotations into a single custom one for less verbosity. This is covered in the spec.

GDF
  • 157
  • 7
0

You could use something like a generic List, adding your values to that List and iterating through.

List<Object> field = new List<Object>

or using Number instead of Object.

Then, your isEmpty() could look like this:

boolean isEmpty() {
    for (Object o : field) {
        if (o == 0) return false;
    return true;
}
Henning
  • 545
  • 1
  • 8
  • 16
  • Nice idea. For mutable (non-final) primitive fields (like `double` with lower-case `d`, etc.) you will need to build the list each time, so I suggest doing it inside the `isEmpty` method. Also a little elaboration or refinement will be needed, but it can be made to work. – Ole V.V. Aug 28 '18 at 11:34