JavaRush /Java блог /Random /Класс MessageFormat
Виталий Рыжаков
40 уровень
Москва

Класс 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 Уровень 34
23 января 2024
Спасибо за статью! Очень хороший класс, полезный и гибкий. Если с ним не знаком то при первом взгляде на код с его использованием, глаза сползают в район 5-й точки. Но на самом деле он очень простой и понятный, просто надо минут 20-30 вникнуть и почитать документацию.
Archy Уровень 48 Expert
8 сентября 2023
Спасибо за статью, в принципе, всё понятно. Но я бы предпочёл всё же использовать String.format и расширенный оператор switch. И количество строк уменьшится, и каждому 2 программисту, открывшему твой код, не придётся разбираться, что за бред ты написал
Vlad Уровень 30
4 апреля 2023
если бы автор написал условие вот так (filelimits[j] <= count && count < filelimits[j+1] ) я бы понял на много быстрее, но и за то что есть большое спасибо.
Мирослав Уровень 29 Expert
30 июня 2022
Условия выбора варианта строки от значения переменной определяются следующим образом: выберется вариант (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
Для тех кто тупит так же как я в этой задаче для начала понимания : Так как вывод текста начинается с "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 Уровень 35
14 апреля 2022
Пока сам не напишешь пару раз разных примеров, в голове не уложиться >_< Или нужно просто отдохнуть..

// аргументы для {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
Я понимаю что здесь Все умные, но если есть такие как я то для задачи 2412 есть MessageFormat pattform = new MessageFormat("{0} {1} | {5} {6}"); и надо в Format[] testFormats = {null, dateFormat, fileform}; добавить еще один нулл. Куда я думаю понять будет не очень трудно.
10 февраля 2022
спасибо, что разжевал )
Роман Уровень 29
22 октября 2021
Сопостовлять нужно 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 Уровень 41
17 июня 2021
Почему нельзя так рассказывать о классах которые там используются перед задачами?😂