Use unchecked exceptions (extending RuntimeException) for preconditions violations, so when a client violates the contract established by the API specification, e.g. negative or exceeding array length index value throws ArrayOutOfBoundsExceptions.
Use checked exceptions (extending Exception) for sitations when API cannot prevent exceptional condition AND the caller can take some useful action when received an exception, e.g. the payment voucher does not have sufficient amount of money to make a purchase. It is important in such case to add an accessor method to the exception informing how to recover, e.g. InsufficientFundsException.getMoneyShortage() – so that the money deficit can be communicated to the client.
Unlike return codes, checked exceptions force developers to handle exceptional conditions, enhancing readibility. However, overuse of checked exceptions makes the API less pleasant to use.