È certamente ragionevole che le interfacce specifichino che le implementazioni non fanno "una cosa". Questo modello può essere visto in C, C ++ e Fortran molto. Vedrai spesso cose chiamate precondizione (prima), postcondition (after), e raramente pericondition (cosa succede mentre la funzione / classe viene eseguita). Questo è stato ulteriormente ampliato in lingue che implementano effettivamente costrutti linguistici sotto forma di contratti . Spesso si vedono le condizioni pre e post su una funzione di template C ++, che definisce cosa può e non può essere usato al suo interno, quali proprietà deve avere il template (generics in java), ecc, nonostante non ci sia modo di farla rispettare (senza una metamodifica template molto difficile)
Nel tuo caso, tuttavia, non sono sicuro che l'intera classe debba essere immutabile o se solo la tua funzione debba essere immutabile invece dell'intera classe.
Nella tua situazione, invece di fornire limiti definiti dalla documentazione, potresti essere in grado di definire una classe che conterrà i dati a cui non vuoi accedere (presumendo che tu sappia anche cosa sia) che implementa solo gli accessor (che potrebbe essere tutto definitivo) e avere quella classe implementare l'interfaccia (o fornire un metodo astratto) per "eseguire". Non puoi garantire l'immutabilità nell'intera classe, ma puoi applicarla su un sottoinsieme di valori che conosci. Puoi anche usare la parola chiave final nella stessa classe astratta per ottenere un effetto simile (ma potrebbe essere più difficile da realizzare)
In altri linguaggi (come C ++) anche senza contratti è possibile forzare una funzione in "const", il che significa che non modifica la classe chiamante. Java rende queste cose particolarmente difficili da realizzare.