Я читал этот вопрос о SO, который обсуждает некоторые общие неопределенные поведения в C ++, и я задавался вопросом: есть ли у Java также неопределенное поведение?
Если это так, то каковы некоторые распространенные причины неопределенного поведения в Java?
Если нет, то какие функции Java делают его свободным от такого поведения и почему последние версии C и C ++ не были реализованы с этими свойствами?
java
c++
c
undefined-behavior
Восемь
источник
источник
Ответы:
В Java вы можете считать поведение некорректно синхронизированной программы неопределенным.
Java 7 JLS использует слово «undefined» один раз, в 17.4.8. Требования к исполнению и причинности :
Документация по Java API описывает некоторые случаи, когда результаты не определены, например, в (устаревшем) конструкторе Date (int year, int month, int day) :
Javadocs для состояния ExecutorService.invokeAll (Collection) :
Менее формальный вид «неопределенного» поведения можно найти, например, в ConcurrentModificationException , где в документах API используется термин «лучшее усилие»:
аппендикс
Один из комментариев к вопросу относится к статье Эрика Липперта, в которой содержится полезное введение в тему: поведение, определяемое реализацией .
Я рекомендую эту статью для независимой от языка аргументации, хотя стоит помнить, что автор нацелен на C #, а не на Java.
Выше только очень краткое освещение; полная статья содержит объяснения и примеры для пунктов, упомянутых в этом отрывке; это много чтения стоит. Например, подробности, приведенные для «шестого фактора», могут дать представление о мотивации для многих операторов в модели памяти Java ( JSR 133 ), помогая понять, почему некоторые оптимизации допускаются, что приводит к неопределенному поведению, в то время как другие запрещены, что приводит к ограничения, такие как « предвидеть» и требования причинности .
источник
Вдобавок ко всему, я не думаю, что в Java есть какое-то неопределенное поведение, по крайней мере, в том же смысле, что и в C ++.
Причина этого в том, что за Java стоит другая философия, чем за C ++. Основная цель разработки Java состояла в том, чтобы позволить программам работать без изменений на разных платформах, поэтому спецификация определяет все очень явно.
Напротив, основной целью проектирования C и C ++ является эффективность: не должно быть каких-либо функций (включая независимость от платформы), которые снижают производительность, даже если они вам не нужны. С этой целью спецификация намеренно не определяет некоторые виды поведения, поскольку их определение может привести к дополнительной работе на некоторых платформах и, следовательно, к снижению производительности даже для людей, которые пишут программы специально для одной платформы и знают обо всех ее особенностях.
Есть даже пример, когда Java была вынуждена задним числом ввести ограниченную форму неопределенного поведения именно по этой причине: ключевое слово strictfp было введено в Java 1.2, чтобы позволить вычислениям с плавающей запятой отклоняться от точного следования стандарту IEEE 754, как ранее требовала спецификация потому что это требовало дополнительной работы и замедляло все вычисления с плавающей точкой на некоторых распространенных процессорах, в то время как в некоторых случаях это приводило к худшим результатам.
источник
int x=-1; foo(); x<<=1;
гиперсовременную философию, предпочтение отдается переписыванию,foo
поэтому любой путь, который не выходит, должен быть недоступен. Это, еслиfoo
этоif (should_launch_missiles) { launch_missiles(); exit(1); }
компилятор может (и по мнению некоторых людей , должны) упростить , что простоlaunch_missiles(); exit(1);
. Традиционным UB было выполнение случайного кода, но раньше оно было связано с законами времени и причинности. Новый улучшенный UB не связан ни с кем.Java очень старается уничтожить неопределенное поведение, именно из-за уроков более ранних языков. Например, переменные уровня класса автоматически инициализируются; локальные переменные не инициализируются автоматически по соображениям производительности, но существует сложный анализ потока данных, чтобы никто не смог написать программу, способную обнаружить это. Ссылки не являются указателями, поэтому недопустимые ссылки не могут существовать, а разыменование
null
вызывает конкретное исключение.Конечно, остаются некоторые поведения, которые не полностью определены, и вы можете писать ненадежные программы, если вы предполагаете, что это так. Например, если вы перебираете обычный (не отсортированный)
Set
язык, он гарантирует, что вы увидите каждый элемент ровно один раз, но не в том порядке, в котором вы их увидите. Порядок может быть таким же на последовательных прогонах, или он может измениться; или он может остаться прежним, пока не произойдет никаких других распределений, или пока вы не обновите свой JDK и т. д. Избавиться от всех таких эффектов практически невозможно ; например, вам придется явно упорядочить или рандомизировать все операции с коллекциями, а это просто не стоит небольшого дополнительного неопределенного неопределенности.источник
Вы должны понимать «неопределенное поведение» и его происхождение.
Неопределенное поведение означает поведение, которое не определено стандартами. В C / C ++ слишком много разных реализаций компилятора и дополнительных функций. Эти дополнительные функции привязали код к компилятору. Это было потому, что не было никакого централизованного развития языка. Таким образом, некоторые из расширенных функций некоторых компиляторов стали «неопределенным поведением».
Принимая во внимание, что в Java спецификация языка контролируется Sun-Oracle, и больше никто не пытается создавать спецификации, и, следовательно, нет неопределенного поведения.
Отредактировано Конкретно отвечая на вопрос
источник
Java устраняет практически все неопределенное поведение, встречающееся в C / C ++. (Например: целочисленное переполнение со знаком, деление на ноль, неинициализированные переменные, разыменование нулевого указателя, смещение больше, чем на битовую ширину, двойное освобождение, даже «нет новой строки в конце исходного кода».) Но в Java есть несколько неясных неопределенных поведений, которые редко встречаются программистами.
Собственный интерфейс Java (JNI), способ для Java вызывать код C или C ++. В JNI есть много способов облажаться, например, неправильно указывать сигнатуру функции, делать недопустимые вызовы служб JVM, повреждать память, неправильно распределять / освобождать данные и т. Д. Я делал эти ошибки раньше, и обычно вся JVM падает, когда какой-либо поток, выполняющий код JNI, совершает ошибку.
Thread.stop()
, что устарело. Quote:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
источник