# Java: Example - Roman Numerals

This is a decimal to roman numeral conversion program. It accepts decimal numbers in the range 1 to 3999. The Romans didn't build their empire with only this small range of numbers, but this restricted range is used because their extended notation doesn't translate well into ASCII characters, for example, bars over numbers (meaning multiply by 1000) and a backward C were common, but many other symbols have been used. And contrary to popular opinion, they did have zero, written as N (nullus or nihil) or as a dash. And there were variations, so you might find other possibilities. The advantage of the hindu-arabic number system that we now use is the positional power notation, which makes computation vastly easier.

This program illustrates a few things:

- A simple GUI.
- Separation of the user interface from the logic / model. In this case the logic is a static method that converts from an internal integer to a roman numeral string.
- A static inner value class is used in the logic class. This could be replaced with parallel arrays.
- Throw and catch exceptions.

## User interface

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
    // File   : gui/componenents/calculators/Dec2Rom.java
    // Description: Converts decimal to roman numerals.
    // Shows  : Simple GUI, anonymous inner class listener.
    //          Separate logic.
    // Author : Fred Swartz - 2006-12-29 - Placed in public domain.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.event.*;

    //////////////////////////////////////////////////////////////// Dec2Rom
    public class Dec2Rom extends JFrame {

        //=============================================== instance variables
        private JTextField _decimalTf = new JTextField(6);
        private JTextField _romanTf   = new JTextField(8);

        //============================================================= main
        public static void main(String[] args) {
            Dec2Rom win = new Dec2Rom();
        }

        //====================================================== constructor
        public Dec2Rom() {
            JButton convertButton = new JButton("Convert");

            //... Create a listener with anonymous inner class syntax.
            ActionListener doIt = new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    try {
                        int val = Integer.parseInt(_decimalTf.getText());
                        String roman = Roman.int2roman(val);
                        _romanTf.setText("" + roman);
                    } catch (NumberFormatException ex) {
                        _romanTf.setText("Error");
                    }
                }};

            //... Add this same listener to two components.
            convertButton.addActionListener(doIt);
            _decimalTf.addActionListener(doIt);

            //... Create panel, set layout, add components.
            JPanel content = new JPanel();
            content.setLayout(new FlowLayout());
            content.add(_decimalTf);
            content.add(convertButton);
            content.add(_romanTf);

            //... Set characteristics of this window.
            this.setContentPane(content);
            this.setTitle("Decimal to Roman");
            this.pack();                       // Do layout.
            this.setLocationRelativeTo(null);  // Center window.
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
        }
    }

## Model / logic

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
    // File   : gui/componenents/calculators/Roman.java
    // Description: A static method for converting binary integers to Roman numbers.
    // Illustrates: Static inner value class, StringBuffer, throw exceptions.
    // Author : Fred Swartz - 2006-12-29 - Placed in public domain.

    /////////////////////////////////////////////////////////////////// class Roman
    public class Roman {
        //================================================================ constant
        // This could be alternatively be done with parallel arrays.
        // Another alternative would be Pair<Integer, String>
        final static RomanValue[] ROMAN_VALUE_TABLE = {
            new RomanValue(1000, "M"),
            new RomanValue( 900, "CM"),
            new RomanValue( 500, "D"),
            new RomanValue( 400, "CD"),
            new RomanValue( 100, "C"),
            new RomanValue(  90, "XC"),
            new RomanValue(  50, "L"),
            new RomanValue(  40, "XL"),
            new RomanValue(  10, "X"),
            new RomanValue(   9, "IX"),
            new RomanValue(   5, "V"),
            new RomanValue(   4, "IV"),
            new RomanValue(   1, "I")
        };

        //============================================================== int2roman
        public static String int2roman(int n) {
            if (n >= 4000  || n < 1) {
                throw new NumberFormatException("Numbers must be in range 1-3999");
            }
            StringBuffer result = new StringBuffer(10);

            //... Start with largest value, and work toward smallest.
            for (RomanValue equiv : ROMAN_VALUE_TABLE) {
                //... Remove as many of this value as possible (maybe none).
                while (n >= equiv.intVal) {
                    n -= equiv.intVal;            // Subtract value.
                    result.append(equiv.romVal);  // Add roman equivalent.
                }
            }
            return result.toString();
        }

        ///////////////////////////////////////////////////////// inner value class
        private static class RomanValue {
            //============================================================== fields
            //... No need to make this fields private because they are
            //    used only in this private value class.
            int    intVal;     // Integer value.
            String romVal;     // Equivalent roman numeral.

            //========================================================= constructor
            RomanValue(int dec, String rom) {
                this.intVal = dec;
                this.romVal = rom;
            }
        }
    }

## Exercises

1. Provide an additional conversion from roman numerals to decimal.