Input Validation

We often use one-way conditionals to validate the inputs for a method.

For example, assume bank accounts are equipped with passwords and balances:

class Account {
   private double balance;
   private String password;
   public Account(double initBalance, String pw) {
      balance = initBalance;
      password = pw;
   }
   public Account(String pw) {
      balance = 0;
      password = pw;
   }
   public double getBalance(String pw) {
      // validate input
      return balance;
   }
   public void withdraw(double amt, String pw) {
      // validate input
      balance = balance - amt;
   }

   public void deposit(double amt, String pw) {
      // validate input
      balance = balance + amt;
   }

}

Here's a simple test harness:

public class TestAccount {

   public static void main(String[] args) {
      Account checking = new Account(100, "boat");
      checking.withdraw(20, "boat");
      System.out.println("balance = $" + checking.getBalance("boat"));
      checking.withdraw(200, "boat");
      System.out.println("balance = $" + checking.getBalance("boat"));
      checking.withdraw(-20, "boat");
      System.out.println("balance = $" + checking.getBalance("boat"));
      checking.withdraw(20, "boot");
      System.out.println("balance = $" + checking.getBalance("boat"));
   }
}

In the first version we decide to terminate the program using System.exit(1) if the supplied password doesn't match the actual password. If the amount to be deposited or withdrawn doesn't match, we end the method using return:

class Account {
   private double balance;
   private String password;
   public Account(double initBalance, String pw) {
      balance = initBalance;
      password = pw;
   }
   public Account(String pw) {
      balance = 0;
      password = pw;
   }
   public double getBalance(String pw) {
      if (!password.equals(pw)) System.exit(1);
      return balance;
   }
   public void withdraw(double amt, String pw) {
      if (!password.equals(pw)) System.exit(1); // end program
      if (amt <= 0) return; // end method
      if (balance < amt) return; // end method
      balance = balance - amt;
   }

   public void deposit(double amt, String pw) {
      if (!password.equals(pw)) System.exit(1); // end program
      if (amt <= 0) return; // end method
      balance = balance + amt;
   }
}

This works fine, but the poor user needs to be notified of his errors. Traditionally, error messages are written to a special error stream object:

System.err.println("You fool!");

For example, we might try to improve the deposit method as follows:

   public void deposit(double amt, String pw) {
      if (!password.equals(pw))
         System.err.println("Unauthorized!");
         System.exit(1); // end program
      if (amt <= 0)
         System.err.println("amount must be possitive");
         return; // end method
      balance = balance + amt;
   }

Unfortunately, the one-way conditional only allows conditional execution of a single command. Although the indentation suggests that System.exit(1) should only be called if the password is invalid, the compiler ignores indentation and sees our declaration as equivalent to:

   public void deposit(double amt, String pw) {
      if (!password.equals(pw))
         System.err.println("Unauthorized!");
      System.exit(1); // end program, always!
      if (amt <= 0)
         System.err.println("amount must be possitive");
      return; // end method
      balance = balance + amt;
   }

Block Commands

Fortunately, multiple commands can be grouped together into a single command using blocks. A block is a sequence of commands, each terminated by a semi-colon and delimited by curly braces:

{COMMAND; COMMAND; COMMAND; ...; COMMAND;}

Blocks can be conditionally evaluated. Here's the next version of Account:

class Account {
   private double balance;
   private String password;
   public Account(double initBalance, String pw) {
      balance = initBalance;
      password = pw;
   }
   public Account(String pw) {
      balance = 0;
      password = pw;
   }
   public double getBalance(String pw) {
      if (!password.equals(pw)) {
         System.err.println("Unauthorized!");
         System.exit(1);
      }
      return balance;
   }
   public void withdraw(double amt, String pw) {
      if (!password.equals(pw)) {
         System.err.println("Unauthorized!");
         System.exit(1); // end program
      }
      if (amt <= 0) {
         System.err.println("Amount must be positive");
         return; // end method
      }
      if (balance < amt) {
         System.err.println("Insufficient funds");
         return; // end method
      }
      balance = balance - amt;
   }

   public void deposit(double amt, String pw) {
      if (!password.equals(pw)) {
         System.err.println("Unauthorized!");
         System.exit(1); // end program
      }
      if (amt <= 0) {
         System.err.println("Amount must be positive");
         return; // end method
      }
      balance = balance + amt;
   }

}

A final problem is how to handle a negative initial balance. We can't use a return command in a constructor. And shutting down the program seems a bit Draconian. One solution is to set the balance to 0, but this requires a two-way conditional:

   public Account(double initBalance, String pw) {
      if (initBalance < 0) {
         System.err.println("Balance must be non-negative, setting balance to $0");
         balance = 0;
      } else {
         balance = initBalance;
      }
      password = pw;
   }

How can this be done without using 2-way conditionals?

TestAccount.java