A Brief Experiment in Rewriting Java with Scala

2018-12-14

Origin

I wanted to implement a Markdown parser in Java and have so far completed support for multi-level headings. The basic approach is to use regular expressions to match and replace the corresponding content. The program is still simple at this stage, and its main flow is as follows:

main process

Reimplementation

Following the same process, I used Scala to implement this functionality, and I will continue to develop it using Scala. First, let’s read the file content. For IO operations, I referred to the “Scala Cookbook,” and it can be done in a single line of code:

var srcLines = Source.fromFile(srcFile).getLines().toList

Compared to verbose Java, Scala is indeed more concise. This is the method I previously used to read files in Java:

/**
  * Read file content
  *
  * @param src File path to read
  * @return File content
  */
private static String readFile(String src) throws IOException {
    StringBuffer content = new StringBuffer();
    InputStream is = null;
    BufferedReader reader = null;

    is = new FileInputStream(src);
    reader = new BufferedReader(new InputStreamReader(is));

    String line = reader.readLine();
    while (line != null) {
        content.append(line);
        content.append("\n");
        line = reader.readLine();
    }

    if (reader != null) {
        reader.close();
    }
    if (is != null) {
        is.close();
    }
    return content.toString();
}

The reason for converting the string to list operations in the Scala version is that there are differences between Scala and Java in using regex matching and replacement APIs. Java uses the Matcher object for iteration, which has methods for finding and replacing:

replace process

In contrast, Scala’s Regex object has methods like findAllMatchIn and replaceAllIn, but the find method’s object is only for searching, and the replace method cannot locate the matched content. Therefore, in Scala, the file is read into a list, and the text content is traversed with indexes as follows:

List.range(0, srcLines.size).foreach(index => {
  srcLines = srcLines.updated(index, regexReplace)
})

Whether or not the regular expression matches, every iteration updates the list by replacing the original item with the transformed content. This approach may not be ideal, and I will continue to watch for and address performance problems. Even from this small example, Scala’s programming style is visibly different from conventional object-oriented Java.

Finally, regarding file writing, the SDK does not provide a specialized operation object, so you can use the PrintWriter from JDK:

val pw = new PrintWriter(new File(outFile))
pw.write(outString)
pw.close()

Future Work

“Scala is a language that grows with developers,” and I will use it to complete my graduation project.