I keep getting stuck conceptually on deciding an Exception-handling structure for my project.
Suppose you have, as an example:
public abstract class
You should declare some kind of exception on the abstract read() method. The abstract class is effectively declaring an interface - and you already know from your two concrete subclasses that an implementation may well be unable to return successfully due to an exception condition.
Thus declaring some exception to be thrown in the abstract Data.read() method is entirely correct. Don't be tempted to simple declare that it throws IOException, as it shouldn't be tied to and of the specific implementations (else you'd have to declare that it could throw SQLException too in case you ever decide to have a database-reading subclass, SAXException in case you ever have an XML-based reader (that uses SAX), and so on). You'll need a custom exception of your own that adequately captures this at the abstract level - something like the DataException recommended above, or potentially reuse an existing custom exception from the same package if this makes sense.