Кодировки в Java
Aleksandr KuzmichevГде мы можем споткнуться о кодировки в Java? Давай разберемся.
Простейший процесс разработки Java-приложения состоит трех из шагов:
1. создать в блокноте файл с java кодом
2. скомпилировать этот файл с помощью команды javac
3. запустить этого файла с помощью команды java (отправляем скомпилированный класс JVM-ке)
Сценарий прост - как фисташку открыть. Но он насквозь пронизан работой с кодировками. Кодировка - это таблица где каждому символу соответствует какое-то число. В памяти символы хранятся как числа - числа из таблицы кодировки. Пример ASCII кодировки для чуть большей наглядности:

Кодировки бывают разными - как правило все включают в себя буквы английского алфавита и общепринятые символы типа тех что вы видите на числовом ряде клавиатуры. А вот символы других языков могут присутствовать, а могут не присутствовать в определенной кодировке. А могут присутствовать, но с другим номером. Т.е. если в памяти лежит число 165 - разной кодировкой он прочитается по разному:
UTF-8: ¥
CP1251: Х (русская)
KOI8-R: И
Именно во время таких несоответствий (файл закодирован одной кодировкой, а читаем мы его другой) - рождаются кракозябры, типа такого:
ÇÒÁÍÏÔÁ ÏÔ ëÕÚØÍÉÞÁ
ÓàÐÜÞâÐ Þâ ºã×ìÜØçÐ
╨│╤А╨░╨╝╨╛╤В╨░ ╨╛╤В ╨Ъ╤Г╨╖╤М╨╝╨╕╤З╨░
Вернемся к нашему сценарию разработки Java-приложения в Windows системе и разберем четыре места встречи с кодировками, каждое представлено этапом на картинке:

1. file encoding
Для начала - созданный App.java файл сохраняется в какой-то конкретной кодировке. Чаще всего - это UTF-8, но могут быть и другие варианты. Следите за тем в какой кодировке сохраняете свой файл, на следующих этапах это будет важно.
2. compilator encoding
Далее - мы хотим что бы компилятор обработал наш файл - для этого компилятору нужно знать с помощью какой кодировки прочитать наш файл. По умолчанию javac будет использовать дефолтную кодировку операционной системы. Хорошо если это например UTF-8. И плохо если это что-то другое, например windows-1251. Символы в ней хранятся уже в другом порядке, и тут начинается проблема с кириллицей - поэтому мы и используем флаг
javac -encoding UTF-8 App.java
чтобы подсказать компилятору как правильно прочитать наш App.java файл.
3. JVM encoding
Хочется сказать что теперь мы подстелили соломку - но есть еще два места где все может пойти не так.
Во-первых, когда мы вызовем -
java App
- JVM тоже попробует использовать дефолтную кодировку при операциях ввода\вывода, в т.ч. для печати данных в консоль. И тут мы тоже можем напороться на то, что App.class был скомпилирован в UTF-8, а данные из него мы будем отправлять на печать снова в windows-1251. Чтобы этого не произошло - используем флаг
java -Dfile.encoding=UTF-8 EncodingTest
4. console encoding
Ура? Нет! Консоль с которой вы работаете (windows cmd / powershell / bash) и куда java будет сыпать строки из System.out.println() - тоже имеет кодировку! Например в windows кодировку консоли можно узнать через команду 'chcp', а если вы увидели там что-то незнакомое - можете поменять ее на кодировку 65001 (это аналог UTF-8 в Windows.):
chcp 65001
И только после всех этих шагов и нюансов нас ожидает счастливый конец. Хотя для старых версий powershell потребуется особая щепотка магии, но об этом как-нибудь в другой раз.