JavaRush/Java блог/Random/Класс MessageFormat

Класс MessageFormat

Статья из группы Random
участников
В этой статье я хочу рассказать о классе MessageFormat, который используется в задаче 2412 (task2412). Класс MessageFormat - 1Класс MessageFormat предназначен для создания строк. Данный класс Java принимает набор объектов, форматирует их, а затем вставляет форматированные строки в шаблон в соответствующих местах. Это своего рода альтернатива (или даже дополнение) к статическому методу String.format. Для начала простой пример использования данного Java класса без создания объекта, а используя статический метод:
int planet = 7;
String event = "a disturbance in the Force";
String result = MessageFormat.format(
        "At {0, time, medium} on {0, date}, there was {1} on planet {2, number, integer}.",
        new Date(), event, planet);
System.out.println(result);
Здесь вызывается статический метод MessageFormat.format, в который передаются аргументами шаблон строки и, собственно, объекты, которые будут вставлены в места, ограниченные скобками {}. В скобках задается позиция объекта начиная с 0, а также тип форматирования, если таковой имеется. Вывод будет такой:
At 21:25:54 on 28 апр. 2018 г., there was a disturbance in the Force on planet 7.
В следующем примере уже создается объект класса MessageFormat:
int fileCount = 1273;
String diskName = "MyDisk";
Object[] testArgs = {fileCount, diskName};

MessageFormat form = new MessageFormat(
        "The disk \"{1}\" contains {0} file(s).");

System.out.println(form.format(testArgs));
При создании объекта класса MessageFormat в его конструктор передается шаблон строки. Далее, при вызове метода format у объекта, туда в качестве аргумента передается массив объектов, которые будут вставлены в шаблон строки. Вывод будет такой:
The disk "MyDisk" contains 1 273 file(s).
Также возможно сделать так, что в зависимости от значения переменной будет выбираться необходимый текст. Своего рода реализация оператора if...else, только с помощью класса ChoiceFormat. Вот код:
MessageFormat form = new MessageFormat("Я могу {1} {0}.");
int count = 2;
String exercise = "подтянуться";
Object[] testArgs = {count, exercise};

double[] filelimits = {0,2,5};
String[] filepart = {"{0} раз","{0} раза","{0} раз"};
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
form.setFormatByArgumentIndex(0, fileform);

System.out.println(form.format(testArgs));
Данный код в зависимости от значения переменной count меняет вывод строки следующим образом:
  • если count = 1 вывод будет такой

    Я могу подтянуться 1 раз.
  • если count = 2 вывод будет такой

    Я могу подтянуться 2 раза.
  • если count = 7 вывод будет такой

    Я могу подтянуться 7 раз.
В данном коде создается массив double[] filelimits, в котором указываются пределы значений, при которых будет меняться вывод строк. А в массиве String[] filepart указываются те самые варианты строк, которые могут быть использованы. Условия выбора варианта строки от значения переменной определяются следующим образом: выберется вариант filepart[j], если filelimits[j] =< count < filelimits[j+1]. Далее создается объект ChoiceFormat fileform и в его конструктор передаются массивы double[] filelimits и String[] filepart. С помощью метода form.setFormatByArgumentIndex(0, fileform) мы говорим объекту MessageFormat form, что когда вызовут метод format, то для индекса 0 в шаблоне строки используй форматирование, которое было задано в объекте ChoiceFormat fileform. Хорошо. У вас уже в принципе могла появиться мысль никогда не использовать Java класс MessageFormat, но знайте, что это еще не все примочки. Имеется вот такой код:
MessageFormat pattform = new MessageFormat("There {0} on {1}.\n{2} {2}");
int count = 0;
Date date = new Date();
Object[] testArgs = {count, "ADisk", date, date};

double[] filelimits = {0,1,2};
String[] filepart = {"are no files","is one file","are {0} files"};
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);

Format[] testFormats
        = {fileform, null, DateFormat.getDateInstance(DateFormat.SHORT), DateFormat.getTimeInstance(DateFormat.SHORT)};
pattform.setFormats(testFormats);

System.out.println(pattform.format(testArgs));
Здесь основная фишка в массиве Format[] testFormats. В данный массив мы заносим объекты (реализующие абстрактный класс Format), которые отвечают за форматирование объектов, определенных в массиве Object[] testArgs. Если объект не нуждается в форматировании, то в массиве Format[] testFormats записывается null. Далее с помощью метода pattform.setFormats(testFormats) мы говорим объекту MessageFormat pattform, что для всех индексов в шаблоне строки надо использовать форматирование, определенное в массиве Format[] testFormats. Для данного примера вывод будет такой:
There are no files on ADisk.
28.04.18 22:10
На этом все и я надеюсь, что при решении задачи 2412 у вас не возникнет сложностей.
Комментарии (49)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Denis Odesskiy Full Stack Developer
23 января, 23:16
Спасибо за статью! Очень хороший класс, полезный и гибкий. Если с ним не знаком то при первом взгляде на код с его использованием, глаза сползают в район 5-й точки. Но на самом деле он очень простой и понятный, просто надо минут 20-30 вникнуть и почитать документацию.
Archy
Уровень 48
Expert
8 сентября 2023, 11:18
Спасибо за статью, в принципе, всё понятно. Но я бы предпочёл всё же использовать String.format и расширенный оператор switch. И количество строк уменьшится, и каждому 2 программисту, открывшему твой код, не придётся разбираться, что за бред ты написал
Vlad
Уровень 30
4 апреля 2023, 08:17
если бы автор написал условие вот так (filelimits[j] <= count && count < filelimits[j+1] ) я бы понял на много быстрее, но и за то что есть большое спасибо.
Мирослав
Уровень 29
Expert
30 июня 2022, 15:43
Условия выбора варианта строки от значения переменной определяются следующим образом: выберется вариант (filepart[j], если filelimits[j] =< count < filelimits[j+1]. Тут не всё ясно!) 🤪 если count > j то j+1 пока не войдет в диапазон double[] fileLimits = {0,2,5} и тогда от индекса(0 или 1 или 2) будет выбран String[] filePart = {"{0} times", "{0} times..", "{0} times"}; и подставлен в формате строки типа ? А тут индекс 0 откуда - form.setFormatByArgumentIndex(0, fileform); Типа переменная count из Object[] tArgs = {count, exercise}; 0-ой индекс ??? В данном выводе кода есть разница и недопонятка int planet = 7; String event = "a disturbance in the Force"; String res = MessageFormat.format( "At {0, time, medium} on {0, date}, there was {1} on planet {2, number, integer}.", ТУТ если убрать (integer) вывод все равно такой--------------------------------------------------------------- new Date(), event, planet); | System.out.println(res); | At 12:45:12 on 07.07.2022, there was a disturbance in the Force on planet 7. <- разница с выводом в лекции такая: Вывод будет такой: At 21:25:54 on 28 апр. 2018 г., there was a disturbance in the Force on planet 7.
Buble76
Уровень 46
13 мая 2022, 10:06
Для тех кто тупит так же как я в этой задаче для начала понимания : Так как вывод текста начинается с "Fake Apple Inc. AAPL |", а сам вывод начинается с создания шаблона в строке
MessageFormat pattform = new MessageFormat("{0}   {1} | {5} {6}");
То делаем вывод что {0} - это вывод названия - Fake Apple Inc. а {1} - это вывод кода - AAPL Далее смотрим как форматируется шаблон при выводе:
Format[] testFormats = {null, dateFormat, fileform};
null - это значит что форматировать данные в данной позиции не надо. Сравниваем шаблон и формат шаблона {0} - формат позиции шаблона - null - т.е. вывод названия не форматируем никак {1} - формат позиции шаблона - ?? - т.е. что делать с выводом кода - не понятно {5} - формат позиции шаблона - вывод форматируем под dateFormat {6} - формат позиции шаблона - вывод форматируем под fileform
defezis Backend Developer в Разработка программн
14 апреля 2022, 15:44
Пока сам не напишешь пару раз разных примеров, в голове не уложиться >_< Или нужно просто отдохнуть..
// аргументы для {0} и {1}
        String who = "Я"; // для {0}..
        int money = 1_000_000;
        Object[] arguments = {who, money}; // это и есть {0}, {1}

 // теперь границы и выбор от "беден" до "сказочно богат", это и будет вставляться вместо {1}
        double[] limits = {0, 10_000, 1_000_000, 10_000_000};
        String[] choice = {
                "беден, в кармане {1} кр.",
                "всё нормально, деньги есть - {1} кр.",
                "богат, в банке {1} кр.",
                "сказочно богат, моё состояние {1} кр."
        };

// настройка messageFormat
        ChoiceFormat choiceFormat = new ChoiceFormat(limits, choice);
        // теперь установить choiceFormat             для {1} аргумента
        messageFormat.setFormatByArgumentIndex(1, choiceFormat);

        System.out.println(messageFormat.format(arguments));
БелК в труселях
Уровень 35
15 февраля 2022, 20:46
Я понимаю что здесь Все умные, но если есть такие как я то для задачи 2412 есть MessageFormat pattform = new MessageFormat("{0} {1} | {5} {6}"); и надо в Format[] testFormats = {null, dateFormat, fileform}; добавить еще один нулл. Куда я думаю понять будет не очень трудно.
10 февраля 2022, 18:47
спасибо, что разжевал )
Роман
Уровень 29
22 октября 2021, 11:49
Сопостовлять нужно testFormats и pattform, а не testFormats и testArgs Из примера это было очень не очевидно, и в задаче 2412 я пытался записать в testFormats 6 значений, т.к. в testArgs их тоже 6 То что нужно сопостоялвять:
Format[] testFormats = {fileform, null, DateFormat.getDateInstance(DateFormat.SHORT), DateFormat.getTimeInstance(DateFormat.SHORT)};
MessageFormat pattform = new MessageFormat("There {0} on {1}.\n{2} {2}");
То что НЕ нужно соповстовлять, но из примера я почему то делал именно это:
Format[] testFormats = {fileform, null, DateFormat.getDateInstance(DateFormat.SHORT), DateFormat.getTimeInstance(DateFormat.SHORT)};
Object[] testArgs = {count, "ADisk", date, date};
Igor Java/Kotlin Developer
17 июня 2021, 08:37
Почему нельзя так рассказывать о классах которые там используются перед задачами?😂