У Java ви можете вважати поведінку неправильно синхронізованої програми невизначеною.
Java 7 JLS використовує слово "undefined" один раз, у 17.4.8. Виконання та вимоги до причинності :
Ми використовуємо f|d
для позначення функції , заданої, обмежуючи область f
в d
. Для всіх x
в d
, f|d(x) = f(x)
і для всіх, що x
не в d
, f|d(x)
не визначено ...
Документація Java API вказує деякі випадки, коли результати не визначені - наприклад, у (застарілому) конструкторі Дата (int рік, int місяць, int день) :
Результат не визначений, якщо даний аргумент виходить за межі ...
Javadocs для стану ExecutorService.invokeAll (колекція) :
Результати цього методу не визначені, якщо дана колекція буде змінена під час цієї операції ...
Менш формальний вид "невизначеної" поведінки можна знайти, наприклад, у ConcurrentModificationException , де документи API використовують термін "найкращі зусилля":
Зауважте, що невдала поведінка не може бути гарантована, оскільки взагалі неможливо дати будь-які жорсткі гарантії за наявності несинхронізованих одночасних модифікацій. Невдалі операції кидаються ConcurrentModificationException
на основі найкращих зусиль . Тому було б неправильно писати програму, яка залежала від цього винятку від її правильності ...
Додаток
Один із коментарів до питань стосується статті Еріка Ліпперта, яка дає корисне вступ до питань теми: поведінка, визначена реалізацією .
Я рекомендую цю статтю для мовно-агностичних міркувань, хоча варто пам’ятати, що автор націлений на C #, а не на Java.
Традиційно ми говоримо, що ідіома мови програмування має невизначену поведінку, якщо використання цієї ідіоми може мати будь-який ефект; він може працювати так, як ви очікуєте, або він може стерти ваш жорсткий диск або збити вашу машину. Крім того, автор укладача не зобов’язаний попередити вас про невизначену поведінку. (Насправді, є деякі мови, в яких програмам, які використовують ідіоми "невизначеної поведінки", мовна специфікація дозволена збивати компілятор!) ...
Навпаки, ідіома, що має поведінку, визначену реалізацією, - це поведінка, де автор компілятора має кілька варіантів того, як реалізувати функцію, і повинен вибрати її. Як випливає з назви, поведінка, визначена реалізацією, принаймні визначена. Наприклад, C # дозволяє впровадженню викидати виняток або створювати значення, коли ціле ділення переповнюється, але реалізація повинна вибрати один. Він не може стерти ваш жорсткий диск ...
Які є фактори, які змушують комітет з розробки мов залишити певні мовні ідіоми як невизначені чи визначені реалізацією поведінки?
Перший головний фактор: чи існують дві існуючі реалізації мови на ринку, які не погоджуються з поведінкою певної програми? ...
Наступним головним фактором є: чи природно ця функція пропонує багато різних можливостей для впровадження, деякі з яких явно кращі за інші? ...
Третій фактор: чи особливість настільки складна, що детальну інформацію про її точну поведінку було б важко або дорого вказати? ...
Четвертий фактор: чи функція покладає на компілятор високий тягар для аналізу? ...
П’ятий фактор: чи ця функція покладає велике навантаження на середовище виконання? ...
Шостий фактор: чи визначає поведінку, що визначається, виключає якусь велику оптимізацію? ...
Це лише декілька факторів, які приходять на думку; Звичайно, є багато, багато інших чинників, про які обговорюють комітети з мовної розробки, перш ніж зробити функцію "визначеною" або "невизначеною".
Зверху - лише дуже коротке висвітлення; повна стаття містить пояснення та приклади до пунктів, зазначених у цьому уривку; це багато читання варто. Наприклад, деталі, наведені для "шостого фактора", можуть дати зрозуміти мотивацію багатьох тверджень у моделі пам'яті Java ( JSR 133 ), що допоможе зрозуміти, чому деякі оптимізації дозволені, що призводить до невизначеної поведінки, а інші заборонені, що призводить до такі обмеження, як вимоги, що відбудуться раніше, та вимоги до причинності .
Жоден із матеріалів статті для мене не є особливо новим, але я буду проклятий, якщо я коли-небудь бачив, як це було представлено настільки елегантним, чітким та зрозумілим способом. Дивовижний.