In Java, è possibile considerare indefinito il comportamento del programma sincronizzato in modo errato.
Java 7 JLS utilizza una volta la parola "non definito", in 17.4.8. Esecuzioni e requisiti di causalità :
Usiamo f|d
per indicare la funzione data limitando il dominio di f
ad
. Per tutti x
in d
, f|d(x) = f(x)
e per tutti x
non in d
, nonf|d(x)
è definito ...
La documentazione dell'API Java specifica alcuni casi in cui i risultati non sono definiti - ad esempio, nella data di costruzione (obsoleta) (int year, int month, int day) :
Il risultato non è definito se un determinato argomento è fuori limite ...
Javadocs per ExecutorService.invokeAll (Collection) dichiara:
I risultati di questo metodo non sono definiti se la raccolta data viene modificata mentre questa operazione è in corso ...
Un tipo meno formale di comportamento "non definito" può essere trovato ad esempio in ConcurrentModificationException , dove i documenti API usano il termine "miglior sforzo":
Si noti che il comportamento fail-fast non può essere garantito in quanto, in generale, è impossibile fornire garanzie concrete in presenza di modifiche simultanee non sincronizzate. Le operazioni fail-fast danno ConcurrentModificationException
il massimo . Pertanto, sarebbe sbagliato scrivere un programma che dipendesse da questa eccezione per la sua correttezza ...
Appendice
Uno dei commenti alle domande fa riferimento a un articolo di Eric Lippert che fornisce un'introduzione utile in argomenti: comportamento definito dall'implementazione .
Consiglio questo articolo per il ragionamento indipendente dal linguaggio, anche se vale la pena ricordare che l'autore ha come target C #, non Java.
Tradizionalmente diciamo che un linguaggio del linguaggio di programmazione ha un comportamento indefinito se l'uso di quel linguaggio può avere qualche effetto; può funzionare nel modo previsto o può cancellare il disco rigido o arrestare in modo anomalo il computer. Inoltre, l'autore del compilatore non ha l'obbligo di avvisarti del comportamento indefinito. (E in effetti, ci sono alcune lingue in cui i programmi che usano idiomi di "comportamento indefinito" sono consentiti dalle specifiche della lingua per bloccare il compilatore!) ...
Al contrario, un linguaggio che ha un comportamento definito dall'implementazione è un comportamento in cui l'autore del compilatore ha diverse scelte su come implementare la funzione e deve sceglierne una. Come suggerisce il nome, il comportamento definito dall'implementazione è almeno definito. Ad esempio, C # consente a un'implementazione di generare un'eccezione o produrre un valore quando trabocca una divisione intera, ma l'implementazione deve sceglierne una. Non è possibile cancellare il disco rigido ...
Quali sono alcuni dei fattori che portano un comitato di progettazione linguistica a lasciare determinati idiomi linguistici come comportamenti indefiniti o definiti dall'implementazione?
Il primo fattore importante è: sul mercato esistono due implementazioni esistenti che non sono d'accordo sul comportamento di un determinato programma?...
Il prossimo fattore importante è: la funzionalità presenta naturalmente molte diverse possibilità di implementazione, alcune delle quali sono chiaramente migliori di altre? ...
Un terzo fattore è: la funzionalità è così complessa che una suddivisione dettagliata del suo comportamento esatto sarebbe difficile o costosa da specificare? ...
Un quarto fattore è: la funzione comporta un onere elevato per il compilatore da analizzare? ...
Un quinto fattore è: la funzione impone un onere elevato all'ambiente di runtime? ...
Un sesto fattore è: rendere il comportamento definito preclude alcune importanti ottimizzazioni? ...
Questi sono solo alcuni dei fattori che mi vengono in mente; ci sono ovviamente molti, molti altri fattori su cui i comitati di progettazione linguistica discutono prima di creare una funzione "implementazione definita" o "non definita".
Sopra è solo una breve copertura; l'articolo completo contiene spiegazioni ed esempi per i punti menzionati in questo estratto; è molto più lettura vale la pena. Ad esempio, i dettagli forniti per il "sesto fattore" possono fornire uno spaccato della motivazione per molte affermazioni nel modello di memoria Java ( JSR 133 ), aiutando a capire perché alcune ottimizzazioni sono consentite, portando a comportamenti indefiniti mentre altri sono proibiti, portando a limiti come accadono prima e requisiti di causalità .
Nessuno dei materiali dell'articolo è particolarmente nuovo per me, ma sarò dannato se lo avessi mai visto presentato in un modo così elegante, conciso e comprensibile. Sorprendente.