VSCodeのJavaフォーマッター

VSCodeでJavaを書くときのフォーマッターは、Language Support for Java(TM) by Red Hatに含まれるEclipse JDTのフォーマッターである。Eclipse形式のフォーマット設定XMLをそのまま読み込めるため、Eclipseで使っていた設定やチームで共有しているスタイル定義を流用できる。

拡張機能のインストール手順は以下の記事で説明している。

【VSCode】Java開発用の設定

フォーマットはコマンドパレット(ctrl+shift+p)からFormat Documentを選ぶと実行される。ショートカットはshift+alt+fである。

フォーマット設定ファイルを指定する

java.format.settings.urlにEclipse形式のフォーマット設定XMLを指定する。

{
  "java.format.settings.url": "/Users/foo/eclipse-formatter.xml"
}

設定ファイルを持っていない場合、Googleのスタイル定義を利用できる。

styleguide/eclipse-java-google-style.xml at gh-pages · google/styleguide

パスの書き方

java.format.settings.urlには次の4つの形式を指定できる。

形式
絶対パス/Users/foo/eclipse-formatter.xml
ホームディレクトリ起点~/eclipse-formatter.xml
ワークスペースルート起点${workspace}/config/formatter.xml
URLhttps://example.com/formatter.xml

${workspace}はワークスペースのルートパスに展開される。リポジトリに設定ファイルを含めてチームで共有する場合は、.vscode/settings.json${workspace}を使って書くとメンバーの環境に依存しない。

{
  "java.format.settings.url": "${workspace}/config/eclipse-formatter.xml"
}

URLを直接指定する場合は、GitHub上のファイルならrawのURLを指定する。

{
  "java.format.settings.url": "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml"
}

プロファイル名を指定する

Eclipseのフォーマット設定XMLは、1つのファイルに複数のプロファイルを含められる。プロファイルはprofile要素のname属性で識別する。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="13">
<profile kind="CodeFormatterProfile" name="GoogleStyle" version="13">
  <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/>
  ...
</profile>
<profile kind="CodeFormatterProfile" name="Narrow" version="13">
  <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="60"/>
  ...
</profile>
</profiles>

使用するプロファイルはjava.format.settings.profileで指定する。

{
  "java.format.settings.url": "${workspace}/config/eclipse-formatter.xml",
  "java.format.settings.profile": "GoogleStyle"
}

java.format.settings.profileを省略すると、ファイル内で最後に定義されたプロファイルが適用される。先頭のプロファイルではないため、複数のプロファイルを含むファイルでは必ずjava.format.settings.profileを指定する。

プロジェクトの設定が優先される

Eclipseのプロジェクトは.settings/org.eclipse.jdt.core.prefsにフォーマット設定を持つ。JDTのフォーマッターはこのファイルをjava.format.settings.urlより優先する。

eclipse.preferences.version=1
org.eclipse.jdt.core.formatter.lineSplit=60

上記の.settings/org.eclipse.jdt.core.prefsがあるプロジェクトでは、java.format.settings.urlに折り返し幅100のスタイル定義を指定していても、60文字で折り返される。

優先されるのはファイルに書かれた項目だけである。.settings/org.eclipse.jdt.core.prefsからorg.eclipse.jdt.core.formatter.lineSplitの行を消すと、java.format.settings.url側の100が適用される。

Eclipseと併用しているプロジェクトでは、Eclipse側で設定した内容がVSCodeにもそのまま反映される。逆に、java.format.settings.urlを指定したのに一部のルールだけ反映されない場合は、.settings/org.eclipse.jdt.core.prefsに同じ項目が残っていないかを確認する。

インデント幅はVSCodeの設定が優先される

フォーマット設定XMLを指定してもインデント幅だけは反映されない。JDTのフォーマッターは、インデント幅とタブ/スペースの選択についてはVSCodeのエディタ設定を優先する。

たとえばGoogleのスタイル定義はインデント2スペースだが、VSCodeのeditor.tabSizeが4のままだと、フォーマット後も4スペースでインデントされる。改行位置や空白の入れ方といった他のルールは設定XMLどおりに適用されるため、「フォーマッターが効いていない」と誤解しやすい。

インデント幅を設定XMLに合わせるには、VSCode側にも同じ値を設定する。

{
  "[java]": {
    "editor.tabSize": 2,
    "editor.insertSpaces": true,
    "editor.detectIndentation": false
  }
}

editor.detectIndentationは既定で有効になっており、ファイルの既存のインデントから幅を推測してeditor.tabSizeを上書きする。フォーマット前のファイルがまちまちのインデントで書かれていると結果が安定しないため、falseにしておく。

GUIでフォーマット設定を編集する

コマンドパレット(ctrl+shift+p)からJava: Open Java Formatter Settings with Previewを選ぶと、フォーマット設定の編集画面が開く。設定項目を変更するとプレビューに結果が即座に反映されるため、XMLを直接編集するより試行錯誤しやすい。

java.format.settings.urlが未設定の場合は新しい設定ファイルを作成できる。編集画面はローカルのファイルのみを対象とするため、URLを指定している場合は.vscodeフォルダへのダウンロードを促される。

保存時にフォーマットする

editor.formatOnSaveを有効にすると保存時にフォーマットされる。

{
  "[java]": {
    "editor.formatOnSave": true
  }
}

"[java]"で囲むとJavaファイルにのみ適用される。他の言語では保存時のフォーマットを避けたい場合に使う。

コメントを整形しない

java.format.comments.enabledfalseにするとコメントがフォーマットの対象から外れる。

{
  "java.format.comments.enabled": false
}

たとえば以下のJavadocは、java.format.comments.enabledが既定のtrueのままだと、説明と@paramの間に空行が挿入され、余分な空白も詰められる。

    /**
     *     ずれた   Javadoc
     * @param args args
     */
    /**
     * ずれた Javadoc
     *
     * @param args args
     */

java.format.comments.enabledfalseにすると、コメントは元のまま残る。アスキーアートの図やコメント内の表を崩したくない場合に有効である。

入力中の自動フォーマットを止める

java.format.onType.enabledは既定で有効になっており、;}、改行を入力したタイミングでブロックが自動的に整形される。入力中に勝手にインデントが変わるのを避けたい場合はfalseにする。

{
  "java.format.onType.enabled": false
}

フォーマッターを無効にする

別のフォーマッター拡張機能を使う場合や、Spotlessなどビルドツール側のフォーマットに任せる場合は、java.format.enabledfalseにしてJDTのフォーマッターを止める。

{
  "java.format.enabled": false
}

一部のコードだけフォーマットしない

配列で表現した行列や、桁を揃えた定数定義など、整形されると読みにくくなるコードがある。@formatter:off@formatter:onのコメントで囲むと、その範囲はフォーマットの対象から外れる。

public class Sample {
    public static void main(String[] args) {
        // @formatter:off
        int[] matrix = {
            1, 0,
            0, 1,
        };
        // @formatter:on
        int[] other = {
            1, 0,
            0, 1,
        };
    }
}

Googleのスタイル定義でフォーマットすると、@formatter:off@formatter:onで囲んだmatrixはそのまま残り、囲んでいないotherは1行にまとめられる。

public class Sample {
    public static void main(String[] args) {
        // @formatter:off
        int[] matrix = {
            1, 0,
            0, 1,
        };
        // @formatter:on
        int[] other = {1, 0, 0, 1,};
    }
}

タグを有効にするには、フォーマット設定XMLでorg.eclipse.jdt.core.formatter.use_on_off_tagstrueになっている必要がある。Googleのスタイル定義では有効になっている。タグの文字列自体もdisabling_tagenabling_tagで変更できる。

<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>

設定一覧

設定既定値内容
java.format.enabledtrueJDTのフォーマッターの有効/無効
java.format.settings.urlなしフォーマット設定XMLのパスまたはURL
java.format.settings.profileなし使用するプロファイル名
java.format.comments.enabledtrueコメントをフォーマットの対象に含めるか
java.format.onType.enabledtrue;}、改行の入力時に自動整形するか

参考