2

I'm writing a little functional Interface and the method that it contains, takes an int as parameter. I was wondering if there's any way to check that when this method will be called, the value passed to the method, will not exceed a certain value and if it does, throw an error. Is there maybe an annotation I can add?

This is what my interface looks like

public interface DrawCardHandler{
    void onDrawCard(int slot);
} 
motelepf
  • 27
  • 5
  • 3
    You could try something like [Design by Contract](https://objectcomputing.com/resources/publications/sett/september-2011-design-by-contract-in-java-with-google). Otherwise, no; you would have to build that kind of validation into the implementation. – Robert Harvey Apr 26 '21 at 19:07
  • As an aside, that implementation looks like one of the few places where Java handily beats C#. AFAICT Microsoft never could get their implementation of Code Contracts to work properly, and this Java implementation looks awesome. – Robert Harvey Apr 26 '21 at 19:11
  • If all you want to do is "throw an error," you can just write `if (slot > maxValue) { throw new IllegalArgumentException(...); }`. – Louis Wasserman Apr 26 '21 at 19:12
  • @LouisWasserman but where would it be possible to write this code? It doesn't seem possible to me to add it to the method while keeping it abstract – motelepf Apr 26 '21 at 19:21
  • Depending on the solution you want to build it may be an option to replace int with a custom type that only may values from a sub range of int. Or maybe even an enum. – Dietmar Höhmann Apr 26 '21 at 19:27
  • 1
    You can't add it to the interface, no. Only to the implementations. You can document that implementations should do the check, but there's nothing you can do to enforce it. – Louis Wasserman Apr 26 '21 at 19:31

1 Answers1

3

Define a class

Rather than pass around a mere int primitive, define a class to represent your specific meaning.

public final class Slot {
    private int value;
    public Slot(int value) {  // Constructor.
        if(/** your check goes here **/) {
            throw new IllegalArgumentException("...");
        }
        this.value = value;
     }
     // getter etc. goes here.
}

In Java 16 and later, use the records feature. A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString. We can choose to write an explicit constructor to validate the input.

public record Slot (int value) {
    public Slot(int value) {  // Constructor.
        if(/** your check goes here **/) {
            throw new IllegalArgumentException("...");
        }
        this.value = value;
    }
    // The getters, equals & hashCode, and toString are implicitly created by compiler.
}

Then your interface could look like:

public interface DrawCardHandler{
    void onDrawCard(Slot slot);
} 

Define an enum

In general, if you know all possible slots in advance, you can create an enum for Slot instead of a class like I've shown - it will be even more expressive.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • Yep. That's pretty much stock standard validation. – Robert Harvey Apr 26 '21 at 19:41
  • For the `record` solution, given you are only doing validation in the constructor I would suggest a compact constructor. You can remove the method arguments and the explicit `this.value = value` assignment and just have the validation code. See https://blogs.oracle.com/javamagazine/records-come-to-java#anchor_7 – sprinter Apr 27 '21 at 03:20