Хочу поделиться своими мыслями о том, почему это происходит.
Предположим, у нас есть файл, в котором хранится нужный нам текст. Чтобы поработать с этим текстом в Java нам нужно загнать данные в String. Как это сделать?
String readFile(String fileName, String encoding) {
StringBuilder out = new StringBuilder();
char buf[] = new char[1024];
InputStream inputStream = null;
Reader reader = null;
try {
inputStream = new FileInputStream(fileName);
reader = new InputStreamReader(inputStream, encoding);
for (int i = reader.read(buf); i >= 0; i = reader.read(buf)) {
out.append(buf, 0, i);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String result = out.toString();
return result;
}
Обратите внимание, что для чтения файла недостаточно просто знать его имя. Нужно еще знать, в какой кодировке в нем находятся данные. Двоичное представление символов в памяти Java-машины и в файле на жестком диске практически никогда не совпадает, поэтому нельзя просто взять и скопировать данные из файла в строку. Сначала нужно получить последовательность байт, а уже потом произвести преобразование в последовательность символов. В приведенном примере это делает класс InputStreamReader.
Код получается достаточно громоздким при том, что необходимость в преобразовании из байтов в символы и обратно возникает очень часто. В связи с этим логичным было бы предоставить разработчику вспомомогательные функции и классы, облегчающие работу по перекодировке. Что для этого сделали разработчики Java? Они завели функции, которые не требуют указания кодировки. Например, класс InputStreamReader имеет конструктор с одним параметром типа InputStream.
String readFile(String fileName) {
StringBuilder out = new StringBuilder();
char buf[] = new char[1024];
try (
InputStream inputStream = new FileInputStream(fileName);
Reader reader = new InputStreamReader(inputStream);
) {
for (int i = reader.read(buf); i >= 0; i = reader.read(buf)) {
out.append(buf, 0, i);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String result = out.toString();
return result;
}
Стало чуть попроще. Но здесь разработчики Java закопали серьезные грабли. В качестве кодировки для преобразования данных они использовали так называемый «default character encoding».
Default charset устанавливается Java-машиной один раз при старте на основании данных взятых из операционной системы и сохраняется для информационных целей в системном свойстве file.encoding. В связи с этим возникают следующие проблемы.
- Кодировка по умолчанию — это глобальный параметр. Нельзя установить для одних классов или функций одну кодировку, а для других — другую.
- Кодировку по умолчанию нельзя изменить во время выполнения программы.
- Кодировка по умолчанию зависит от окружения, поэтому нельзя заранее знать, какая она будет.
- Поведение методов, зависящих от кодировки по умолчанию, нельзя надежно покрыть тестами, потому что кодировок достаточно много, и множество их значений может расширяться. Может выйти какая-нибудь новая ОС с кодировкой типа UTF-48, и все тесты на ней окажутся бесполезными.
- При возникновении ошибок приходится анализировать больше кода, чтобы узнать, какую именно кодировку использовала та или иная функция.
- Поведение JVM в случае изменения окружения после старта становится непредсказуемо.
Но главное — это то, что от разработчика скрывается важный аспект работы программы, и он может просто не заметить, что использовал функцию, которая в разном окружении будет работать по-разному. Класс FileReader вообще не содержит функций, которые позволяют указать кодировку, хотя сам класс логичен и удобен, поэтому он стимулирует пользователя на создание платформозависимого кода.
Из-за этого происходят удивительные вещи. Например, программа может неправильно открыть файл, который ранее сама же создала.
Или, скажем, есть у нас XML-файл, у которого в заголовке написано encoding=«UTF-8», но в Java-программе этот файл открывается при помощи класса FileReader, и привет. Где-то откроется нормально, а где-то нет.
Особенно ярко проблема file.encoding проявляется в Windows. В ней Java в качестве кодировки по умолчанию использует ANSI-кодировку, которая для России равна Cp1251. В самой Windows говорится, что «этот параметр задает язык для отображения текста в программах, не поддерживающих Юникод». При чем здесь Java, которая изначально задумывалась для полной поддержки Юникода, непонятно, ведь для Windows родная кодировка — UTF-16LE, начиная где-то с Windows 95, за 3 года до выхода 1-й Java.
Так что если вы сохранили при помощи Java-программы файл у себя на компьютере и отправили его вашему коллеге в Европу, то получатель при помощи той же программы может и не суметь открыть его, даже если версия операционной системы у него такая же как и у вас. А когда вы переедете с Windows на Mac или Linux, то вы уже и сами свои файлы можете не прочитать.
А ведь еще есть Windows консоль, которая работает в OEM-кодировке. Все мы наблюдали, как вплоть до Java 1.7 любой вывод русского текста в черном окне при помощи System.out выдавал крокозябры. Это тоже результат использования функций, основанных на default character encoding.
Я у себя проблему кодировок в Java решаю следующим образом:
- Всегда запускаю Java с параметром -Dfile.encoding=UTF-8. Это позволяет убрать зависимость от окружения, делает поведение программ детерминированным и совместимым с большинством операционных систем.
- При тестировании своих программ обязательно делаю тесты с нестандартной (несовместимой с ASCII) кодировкой по умолчанию. Это позволяет отловить библиотеки, которые пользуются классами типа FileReader. При обнаружении таких библиотек стараюсь их не использовать, потому что, во-первых, с кодировками обязательно будут проблемы, а во-вторых, качество кода в таких библиотеках вызывает серьезные сомнения. Обычно я запускаю java с параметром -Dfile.encoding=UTF-32BE, чтобы уж наверняка.
Это не дает стопроцентной гарантии от проблем, потому что есть же еще и лаунчеры, которые запускают Java в отдельном процессе с теми параметрами, которые считают нужными. Например, так делали многие плагины к анту. Сам ант работал с file.encoding=UTF-8, но какой-нибудь генератор кода, вызываемый плагином, работал с кодировкой по умолчанию, и получалась обычная каша из разных кодировок.
По идее, со временем код должен становиться более качественным, программы более надежными, форматы более стандартизованными. Однако этого не происходит. Вместо этого наблюдается всплеск ошибок с кодировками в Java-программах. Видимо, это связано с тем, что в мир Java иммигрировали люди, не привыкшие решать проблему кодировок. Скажем, в C# по умолчанию применяется кодировка UTF-8, поэтому разработчик, переехавший с C#, вполне разумно считает, что InputStreamReader по умолчанию использует эту же кодировку, и не вдается в детали его реализации.
Недавно наткнулся на подобную ошибку в maven-scr-plugin.
Но настоящее удивление пришлось испытать при переезде на восьмерку. Тесты показали, что проблема с кодировкой затесалась в JDK.
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import javax.crypto.Cipher;
public class PemEncodingBugDemo {
public static void main(String[] args) {
try {
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345467890\r\n /=+-";
byte ascii[] = str.getBytes(StandardCharsets.US_ASCII);
byte current[] = str.getBytes(Charset.defaultCharset());
if (Arrays.equals(ascii, current)) {
System.err.printf("Run this test with non-ascii native encoding,%n");
System.err.printf("for example java -Dfile.encoding=UTF-16%n");
}
Cipher.getInstance("RC4");
} catch (Throwable e) {
e.printStackTrace();
}
}
}
На девятке не воспроизводится, видимо, там уже починили.
Поискав по базе ошибок, я нашел еще одну недавно закрытую ошибку, связанную с теми же самыми функциями. И что характерно, их даже исправляют не совсем правильно. Коллеги забывают, что для стандартных кодировок, начиная с Java 7, следует использовать константы из класса StandardCharsets. Так что впереди, к сожалению, нас ждет еще масса сюрпризов.
Запустив grep по исходникам JDK, я нашел десятки мест, где используются платформозависимые функции. Все они будут работать некорректно в окружении, где родная кодировка, несовместима с ASCII. Например, класс Currency, хотя казалось бы, уж этот-то класс должен учитывать все аспекты локализации.
Когда некоторые функции начинают создавать проблемы, и для них существует адекватная альтернатива, давно известно, что нужно делать. Нужно отметить эти функции как устаревшие и указать, на что их следует заменить. Это хорошо зарекомендовавший себя механизм deprecation, который даже планируют развивать.
Я считаю, что функции, зависящие от кодировки по умолчанию, надо обозначить устаревшими, тем более, что их не так уж и много:
Функция | На что заменить |
---|---|
Charset.defaultCharset() | удалить |
FileReader.FileReader(String) | FileReader.FileReader(String, Charset) |
FileReader.FileReader(File) | FileReader.FileReader(File, Charset) |
FileReader.FileReader(FileDescriptor) | FileReader.FileReader(FileDescriptor, Charset) |
InputStreamReader.InputStreamReader (InputStream) | InputStreamReader.InputStreamReader (InputStream, Charset) |
FileWriter.FileWriter(String) | FileWriter.FileWriter(String, Charset) |
FileWriter.FileWriter(String, boolean) | FileWriter.FileWriter(String, boolean, Charset) |
FileWriter.FileWriter(File) | FileWriter.FileWriter(File, Charset) |
FileWriter.FileWriter(File, boolean) | FileWriter.FileWriter(File, boolean, Charset) |
FileWriter.FileWriter(FileDescriptor) | FileWriter.FileWriter(FileDescriptor, Charset) |
OutputStreamWriter.OutputStreamWriter (OutputStream) | OutputStreamWriter.OutputStreamWriter (OutputStream, Charset) |
String.String(byte[]) | String.String(byte[], Charset) |
String.String(byte[], int, int) | String.String(byte[], int, int, Charset) |
String.getBytes() | String.getBytes(Charset) |
Часть программного обеспечения для марсианского зонда Скиапарелли написали на Java, на актуальной в то время версии 1.7. Запустили изделие весной, и путь к месту назначения составил полгода. Пока он летел, в Европейском космическом агентстве обновили JDK.
Ну а что? Разработка софта для нынешней миссии завершена, надо делать ПО уже для следующей, а мы все еще на семерке сидим. НАСА и Роскосмос уже давно на восьмерку перешли, а там лямбды, стримы, интерфейсные методы по умолчанию, новый сборщик мусора, и вообще.
Обновились и перед посадкой отправили на космический аппарат управляющую команду не в той кодировке, в которой он ожидал.
Комментарии (52)
mayorovp
21.11.2016 10:42А тем временем в Microsoft портировали проблему с кодировками из Java в powershell :)
Рекомендуемый всюду способ считывания xml-файлов:
[xml]$xml = Get-Content Путь:\к\файлу.xml
При этом сначала считывается файл в системной кодировке, а потом превращается в DOM. А на то, что в самом файле может быть указана другая кодировка — не важно...
rbobot
21.11.2016 10:48+1Get-Content — не специализированный коммандлет для работы с xml и он не ожидает указания кодировки от файла. Это просто получение содержимого, вся xml магия в приведении.
Вместе с тем, для Get-Content можно указать кодировку параметром -Encoding и не иметь проблем.mayorovp
21.11.2016 11:14+1Это если кодировка файла — известна. А если нет?
Тот же
XmlDocument
, лежащий за синонимом[xml]
, умеет читать любой поток байт, определяя кодировку из декларации. Так же какXmlReader
иXDocument
.
Но в powershell эту возможность так просто использовать не получится — вот и гуляет ошибочное решение по интернету…
rbobot
21.11.2016 15:37-1Ну, если это реально насущная проблема, можно прочитать первую строчку и сматчить из нее кодировку. PS же скриптовый язык и такие вещи тут на каждом углу, иначе получится очередной C# — за простоту и универсальность надо чем-то платить.
mayorovp
21.11.2016 15:46+1Это ж уже велосипед будет… Правильный способ — такой:
$xml = New-Object ([xml]) $xml.Load((Get-Item путь\к\файлу.xml))
Если путь абсолютный — то Get-Item не нужен
Проблема исключительно в том, что в инете советуют способ через Get-Content
rbobot
23.11.2016 13:55Да, и правда лучше, спасибо.
Жуткий формат, я его избегаю постоянно, а тут упала задача как-раз в xml в 1251.
fogone
21.11.2016 10:58+1Чтобы поработать с этим текстом в Java нам нужно загнать данные в String. Как это сделать?
Или еще вот так можно:
String str = new String(Files.readAllBytes(Paths.get("file")), StandardCharsets.UTF_8);
Beholder
21.11.2016 11:06+11NASA широко использует Java, но только на наземных рабочих станциях, в частности для задач анализа и визуализации, но никто не будет её устанавливать непосредственно в аппараты. Так что громкий заголовок очень похож на случай так называемого вранья.
mayorovp
21.11.2016 11:20+4Там же все написано русским по белому! Java стоит не на аппарате, а в центре управления. Пруф конечно же все еще нужен — но ваше возражение совсем не по делу.
TimsTims
21.11.2016 15:07+1> Java стоит не на аппарате
Как же не на аппарате, если вы сами написали:
> Часть программного обеспечения для марсианского зонда Скиапарелли написали на Java
Или вы хотите улизнуть и сейчас скажете: «ну ПО то написали, но это не значит, что оно там используется!»
MzMz
21.11.2016 11:25При чем здесь Java, которая изначально задумывалась для полной поддержки Юникода, непонятно, ведь для Windows родная кодировка — UTF-16LE, начиная где-то с Windows 95, за 3 года до выхода 1-й Java.
У меня например консоль cmd.exe выдает:
H:\>chcp
Active code page: 437
Выводить кириллический текст в нее даже в UTF-8 бесполезно. При этом поставить правильную кодировку еще полдела, надо еще и шрифт поменять на TrueType.
Java оперирует внутри себя 16-битными Unicode сodepoint, но внешний мир жесток и несовершенен (особенно в Windows), поэтому статья правильно акцентирует внимание на том, что про кодировку помнить нужно и проставлять лучше явно. С другой стороны, на правильных операционных системах дефолтная кодировка в 99% работает корректно.mayorovp
21.11.2016 12:30Консоль в винде всегда можно переключить в нужный режим. Кстати, начиная с win10 она даже последовательности VT100 поддерживает, если их включить...
fogone
21.11.2016 12:13+1Надо заметить, что, хотя проблема такая действительно существует, перечисленные в таблице методы — это легаси, существующее для совместимости (которая в мире java очень важна), а все новые api учитывают проблемы дефолтной кодировки и используют UTF8 в качестве кодировки по-умолчанию. Это хороший повод, например, использовать новый api для работы с файловой системой — там эти проблемы учтены, а для чтения файла в строку есть удобные методы, делающие это в одну строку кода.
mayorovp
21.11.2016 12:32+1Так о том и речь, что надо бы им @Deprecated поставить.
Lure_of_Chaos
21.11.2016 13:42Но нет, они @Deprecated поставили именно на Date, который до сих пор никуда не делся и активно используется.
sergey-b
21.11.2016 23:10Беда в том, что этим легаси пользуются вовсю и даже в самом JDK. Привносят с этими методами ошибки туда, где их раньше не было.
fogone
23.11.2016 12:07Да, вероятно, было бы лучше, если бы такие потенциально опасные методы были помечены как @Deprecated. Но где их используют в JDK?
sergey-b
23.11.2016 21:43Например, вот здесь http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/4235be4c9432
fogone
24.11.2016 13:39ну да, но судя по тому, что этот код исправили и указали кодировку явно, это скорее баг, чем намеренно использование этого конструктора. И да, я согласен, что если бы они были @Deprecated, то такие ошибки отлавливать было бы намного проще.
TimsTims
21.11.2016 12:38+4> Найдена причина аварии
Хотя бы сменили бы желтушный заголовок, раз это лишь предположение. Мы ведь не «горячие новости» из smi2 тут читаем, а вполне адекватные посты.
Укажите примерно так:
> Откуда в Java всплывают проблемы с кодировками и возможная причина падения марсианского зонда
Lure_of_Chaos
21.11.2016 13:41+2Статью можно резюмировать так: указывайте кодировку, передавая в соотв. методах параметр Charset — обычно StandardCharsets.UTF_8 хватает, на что указывают современные IDE (отдельное спасибо JetBrains за IDEA и анализатор «из коробки») и анализаторы типа FindBugs — благодаря им столько потенциальных багов было выявлено еще до тестирования!
grossws
22.11.2016 01:57Ещё крайне полезно использовать forbidden-apis checker, умеет ловить следующее:
jdk-unsafe-*
— использование методов jdk, которые неявно используют charset, locale или timezone по умолчанию;jdk-deprecated-*
— использование deprecated методов и jdk;jdk-internal-*
— использование внутренних методов jdk из пакетов, выдаваемых Security.getProperty("package.access");jdk-non-portable
— множество потенциально несовместимых api, включающееjdk-internal
;jdk-system-out
— думаю и так ясно;jdk-reflection
— куски использования reflection, которые должны поломаться в java 9;commons-io-unsafe-*
— использование методов с default charset.
jdk-internal @openjdk 8u122- com.oracle.webservices.internal.
- com.oracle.xmlns.internal.
- com.sun.activation.registries.
- com.sun.corba.se.
- com.sun.imageio.
- com.sun.istack.internal.
- com.sun.jmx.
- com.sun.media.sound.
- com.sun.naming.internal.
- com.sun.org.apache.bcel.internal.
- com.sun.org.apache.regexp.internal.
- com.sun.org.apache.xalan.internal.extensions.
- com.sun.org.apache.xalan.internal.lib.
- com.sun.org.apache.xalan.internal.res.
- com.sun.org.apache.xalan.internal.templates.
- com.sun.org.apache.xalan.internal.utils.
- com.sun.org.apache.xalan.internal.xslt.
- com.sun.org.apache.xalan.internal.xsltc.cmdline.
- com.sun.org.apache.xalan.internal.xsltc.compiler.
- com.sun.org.apache.xalan.internal.xsltc.trax.
- com.sun.org.apache.xalan.internal.xsltc.util.
- com.sun.org.apache.xerces.internal.
- com.sun.org.apache.xml.internal.res.
- com.sun.org.apache.xml.internal.security.
- com.sun.org.apache.xml.internal.serializer.utils.
- com.sun.org.apache.xml.internal.utils.
- com.sun.org.apache.xpath.internal.
- com.sun.org.glassfish.
- com.sun.proxy.
- com.sun.xml.internal.
- jdk.internal.
- jdk.nashorn.internal.
- jdk.nashorn.tools.
- oracle.jrockit.jfr.
- org.jcp.xml.dsig.internal.
- sun.
Lure_of_Chaos
21.11.2016 13:45-1И, кстати, поддержу: почему стандартная кодировка в винде не UTF-8, как в тех же линухах?
MacIn
21.11.2016 21:19+2Когда «в тех же линухах» появилась UTF-8 как стандарт?
Когда в винде появился юникод?
sergey-b
21.11.2016 22:55+2Дело в том, что само понятие стандартной кодировки размыто. Одни программы работают в чистом ASCII, другие UTF-8, функции Win32 работают в UTF-16 или в Ansi. Консоль работает в OEM и легкоп переключается командой chcp. У cygwin своя система локализации. Вполне возможно, что в будущих версиях Windows кодировки могут быть у разных пользователей разные. Какую кодировку считать стандартной, непонятно.
Lure_of_Chaos
21.11.2016 13:47А еще, мы тут на работе словили exception при JAXB анмаршаллинге xml, который приехал с BOM, это было очень весело править :)
dom1n1k
21.11.2016 17:04+1Перед самой посадкой никакие команды на зонд не отправляются (пинг не позволяет), она проходит в автономном режиме.
sergey-b
21.11.2016 23:25Согласен. Перед посадкой что-либо отправлять на аппарат уже бесполезно. В процессе полета обычно производят коррекцию траектории командами с Земли. А посадка производится в полностью автоматическом режиме.
zirix
21.11.2016 21:07-2byte ascii[] = str.getBytes(StandardCharsets.US_ASCII); byte current[] = str.getBytes(Charset.defaultCharset()); // Charset.defaultCharset() == UTF-16 при -Dfile.encoding=UTF-16
Вам не кажется что число байтов(и их значение) в UTF-8 и в UTF-16 будет разное? При этом UTF-8 будет такой же как ASCII если не использовать символы >=127 (в этом моменте могу ошибаться).
Возможно я вас не понял, но тут никакой ошибки в JDK я не вижу.zirix
21.11.2016 21:30-1Читал невнимательно, искал где тут про зонд написано.
Cipher.getInstance(«RC4»); вылетает…
sergey-b
21.11.2016 23:29Это я добавил, чтобы было понятно, в каких условиях работает test case. Ведь установить кодировку по умолчанию изнутри программы невозможно, поэтому тест основывается на том, что его запускают в определенном окружении. Тестировщики, они ведь они такие: прогонят тест и напишут, что «не воспроизводится».
sand14
21.11.2016 22:12Видимо, это связано с тем, что в мир Java иммигрировали люди, не привыкшие решать проблему кодировок. Скажем, в C# по умолчанию применяется кодировка UTF-8, поэтому разработчик, переехавший с C#, вполне разумно считает, что InputStreamReader по умолчанию использует эту же кодировку, и не вдается в детали его реализации.
Java и C#, нужно смотреть контракт класса, который используешь.
В C# действительно при чтении файлов по умолчанию используется UTF8, или определяется по заголовку (для XML) или BOM, если заголовок не определен или отсутствует BOM.
Тем не менее, и тут есть вероятность ошибки автоматического определения кодировки.
А что, если BOM это BOM, а полезные данные? — при создании объекта-кодировки можно указать, использовать ли BOM, когда эта кодировка передается ридеру (и тут тоже есть свои умолчания — использовать BOM).
Поэтому программист тут тоже должен понимать, что именно делает, и принимать решение, что делать.
И в C# хватает своих неоднозначностей — например, использование глобальных настроек CurrentCulture при работе со строками.
vlanko
21.11.2016 22:46Да, важная проблема. Я использовал тупо FileWriter, и при некоторых параметрах он писал китайские иероглифы.
semio
21.11.2016 22:47Что характерно, в классе java.nio.Files, появившемся в java 7, по умолчанию используется UTF-8.
А в библиотеке Guava, в аналогичном классе Files, вообще нет методов, имеющих кодировку по умолчанию (например, Files.toString()).
vadim_mishchenko
21.11.2016 22:47«откуда в Java всплывают проблемы с кодировками» — почему то, что инженер не прочитал что АПИ, стало проблемой Java?
kbac9
21.11.2016 22:51А еще в далеком 2005-ом году, когда робот Томми разбился об стену на гонках роботов, тоже говорили, что Java виновата:)
sadr0b0t
24.11.2016 02:22>Я считаю, что функции, зависящие от кодировки по умолчанию, надо обозначить устаревшими, тем более, что их не так уж и много
Если все начнут хардкодить кодировки, получится еще больший ацкий зоопарк, на который даже параметрами командной строки не повлиять. Просто кодировка по умолчанию должна быть не системная, а на всех платформах всегда и везде — UTF-8. Кому хочется легаси и экзотики — пускай передают параметры или хардкодят через предложенные методы, но в этом случае при каждом запуске приложения и каждом чтении файла должен выскакивать назойливый диалог: «вы используете устаревшую кодировку, настоятельно рекомендуем конвертировать ваши файлы в UTF-8».
selenite
24.11.2016 02:52> Например, так делали многие плагины к анту. Сам ант работал с file.encoding=UTF-8, но какой-нибудь генератор кода, вызываемый плагином, работал с кодировкой по умолчанию, и получалась обычная каша из разных кодировок.
1. окей гугл, исходники openjdk без регистрации.
2. окей, написать обертку для бинарники java, подставляющую нужные аргументы — не вариант?
3. если «не вариант» — тем же easyhook/LD_PRELOAD/%решениенейм% быстро запилить фильтр для запускающихся процессов с целью передачи нужных аргументов. Тем более что для Java на современных машинах под виндой приходится примерно таким образом «портить» обращение к функциям, возвращающим информацию о DPI дисплея ради некоторых древних приложений типа Packet Tracer.
dyakhnov
24.11.2016 06:35А вот и официальный отчет из ESA (расследование еще не завершено):
When merged into the navigation system, the erroneous information generated an estimated altitude that was negative – that is, below ground level. This in turn successively triggered a premature release of the parachute and the backshell, a brief firing of the braking thrusters and finally activation of the on-ground systems as if Schiaparelli had already landed. In reality, the vehicle was still at an altitude of around 3.7 km.
Короче какой-то сенсор послал максимальное значение в компьютер и тот решил включить тормоза и отстрелить парашют.
dyakhnov
А можно ссылку на оригинал: кем найдена причина падения и в чем она заключается? Вроде бы расследование еще не завершено пока…
ainoneko
Что сомнительно: вряд ли команды должны зависеть от кодировки (разве что туда проник автор статьи со своим «параметром -Dfile.encoding=UTF-32BE, чтобы уж наверняка».)
А то можно было бы сделать заголовок ещё лучше: «Java снова не тормозит» (если кто помнит про события 11-летной давности: «Робот под управлением Linux с софтом на Java убился об стену»).