web-dev-qa-db-ja.com

Java 8:改行とインデントを使用してラムダをフォーマットする

ラムダインデントで達成したいことは次のとおりです:

複数行のステートメント:

String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des (M)", "Rick (M)" };
List<String> strings = Arrays.stream(ppl)
                         .filter(
                             (x) -> 
                             {
                                 return x.contains("(M)");
                             }
                         ).collect(Collectors.toList());
strings.stream().forEach(System.out::println);

単一行ステートメント:

List<String> strings = Arrays.stream(ppl)
                         .map((x) -> x.toUpperCase())
                         .filter((x) -> x.contains("(M)"))
                         .collect(Collectors.toList());



現在、Eclipseは次の形式に自動フォーマットしています。

複数行のステートメント:

String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des (M)", "Rick (M)" };
List<String> strings = Arrays.stream(ppl).filter((x) ->
{
    return x.contains("(M)");
}).collect(Collectors.toList());
strings.stream().forEach(System.out::println);

単一行ステートメント:

String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des(M)", "Rick (M)" };
List<String> strings = Arrays.stream(ppl).map((x) -> x.toUpperCase())
        .filter((x) -> x.contains("(M)")).collect(Collectors.toList());
strings.stream().forEach(System.out::println);

collect呼び出しがreturnの直下にあり、間にスペースがないため、これは非常に面倒です。インデントされた新しい行でラムダを開始できれば、.filter(呼び出しは.collect(呼び出し。ただし、標準のJava-8 Eclipse Formatterでカスタマイズできるのは、ラムダ本体の先頭にあるブレースだけですが、()事前に括弧、インデントも。

また、単一行の呼び出しの場合、基本的な行ラップを使用するだけで、連鎖混乱になります。これが後で解読するのが難しい理由を説明する必要はないと思います。

何らかの方法でフォーマットをさらにカスタマイズし、Eclipseで最初のフォーマットタイプを達成する方法はありますか? (または、オプションで、別のIDE IntelliJ IDEAのように。)



編集:IntelliJ IDEA 13 Community Edition(read:無料版:P)で取得できた最も近いものでした。これは、この場合は連続インデントによって定義されます8):

public static void main(String[] args)
{
    int[] x = new int[] {1, 2, 3, 4, 5, 6, 7};
    int sum = Arrays.stream(x)
            .map((n) -> n * 5)
            .filter((n) -> {
                System.out.println("Filtering: " + n);
                return n % 3 != 0;
            })
            .reduce(0, Integer::sum);

    List<Integer> list = Arrays.stream(x)
            .filter((n) -> n % 2 == 0)
            .map((n) -> n * 4)
            .boxed()
            .collect(Collectors.toList());
    list.forEach(System.out::println);
    System.out.println(sum);    

また、次のように連鎖メソッド呼び出しを「整列」することもできます。

    int sum = Arrays.stream(x)
                    .map((n) -> n * 5)
                    .filter((n) -> {
                        System.out.println("Filtering: " + n);
                        return n % 3 != 0;
                    })
                    .reduce(0, Integer::sum);


    List<Integer> list = Arrays.stream(x)
                               .filter((n) -> n % 2 == 0)
                               .map((n) -> n * 4)
                               .boxed()
                               .collect(Collectors.toList());
    list.forEach(System.out::println);
    System.out.println(sum);
}

私は個人的にはそれがより理にかなっているが、2番目のバージョンはそれをあまりにも遠ざけているので、最初のバージョンを好みます。

最初のセットアップを担当するセットアップは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<code_scheme name="Zhuinden">
  <option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
  <option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
  <option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" />
  <option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
  <option name="JD_P_AT_EMPTY_LINES" value="false" />
  <option name="JD_PARAM_DESCRIPTION_ON_NEW_LINE" value="true" />
  <option name="WRAP_COMMENTS" value="true" />
  <codeStyleSettings language="Java">
    <option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
    <option name="BRACE_STYLE" value="2" />
    <option name="CLASS_BRACE_STYLE" value="2" />
    <option name="METHOD_BRACE_STYLE" value="2" />
    <option name="ELSE_ON_NEW_LINE" value="true" />
    <option name="WHILE_ON_NEW_LINE" value="true" />
    <option name="CATCH_ON_NEW_LINE" value="true" />
    <option name="FINALLY_ON_NEW_LINE" value="true" />
    <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
    <option name="SPACE_WITHIN_BRACES" value="true" />
    <option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_TRY_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
    <option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
    <option name="METHOD_PARAMETERS_WRAP" value="1" />
    <option name="EXTENDS_LIST_WRAP" value="1" />
    <option name="THROWS_LIST_WRAP" value="1" />
    <option name="EXTENDS_KEYWORD_WRAP" value="1" />
    <option name="THROWS_KEYWORD_WRAP" value="1" />
    <option name="METHOD_CALL_CHAIN_WRAP" value="2" />
    <option name="BINARY_OPERATION_WRAP" value="1" />
    <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
    <option name="ASSIGNMENT_WRAP" value="1" />
    <option name="IF_BRACE_FORCE" value="3" />
    <option name="DOWHILE_BRACE_FORCE" value="3" />
    <option name="WHILE_BRACE_FORCE" value="3" />
    <option name="FOR_BRACE_FORCE" value="3" />
    <option name="PARAMETER_ANNOTATION_WRAP" value="1" />
    <option name="VARIABLE_ANNOTATION_WRAP" value="1" />
    <option name="ENUM_CONSTANTS_WRAP" value="2" />
  </codeStyleSettings>
</code_scheme>

私はすべてが合理的であることを確認しようとしましたが、何かを台無しにしてしまった可能性があるため、微調整が必​​要になる場合があります。

あなたが私のようなハンガリー人であり、ハンガリー語のレイアウトを使用している場合、このキーマップが役に立つかもしれません。そのため、AltGR + F、AltGR + G、AltGR + Bを使用できなくなることはありません。 、AltGR + NおよびAltGR + M(Ctrl + Altに対応)。

<?xml version="1.0" encoding="UTF-8"?>
<keymap version="1" name="Default copy" parent="$default">
  <action id="ExtractMethod">
    <keyboard-shortcut first-keystroke="shift control M" />
  </action>
  <action id="GotoImplementation">
    <mouse-shortcut keystroke="control alt button1" />
  </action>
  <action id="GotoLine">
    <keyboard-shortcut first-keystroke="shift control G" />
  </action>
  <action id="Inline">
    <keyboard-shortcut first-keystroke="shift control O" />
  </action>
  <action id="IntroduceField">
    <keyboard-shortcut first-keystroke="shift control D" />
  </action>
  <action id="Mvc.RunTarget">
    <keyboard-shortcut first-keystroke="shift control P" />
  </action>
  <action id="StructuralSearchPlugin.StructuralReplaceAction" />
  <action id="Synchronize">
    <keyboard-shortcut first-keystroke="shift control Y" />
  </action>
</keymap>

IntelliJは新しい行にラムダの開きブレースを配置する方法を提供していないようですが、それ以外の場合はかなり合理的な書式設定方法なので、これを承認済みとしてマークします。

72
EpicPandaForce

すぐに使用できるIntelliJ 13がおそらく動作します。

このように書くと:

// Mulit-Line Statement
String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des (M)", "Rick (M)" };
List<String> strings = Arrays.stream(ppl)
        .filter(
                (x) ->
                {
                    return x.contains("(M)");
                }
        ).collect(Collectors.toList());
strings.stream().forEach(System.out::println);

そして、自動フォーマッタを適用します(変更なし):

// Mulit-Line Statement
String[] ppl = new String[]{"Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des (M)", "Rick (M)"};
List<String> strings = Arrays.stream(ppl)
        .filter(
                (x) ->
                {
                    return x.contains("(M)");
                }
        ).collect(Collectors.toList());
strings.stream().forEach(System.out::println);

同じことが単一行ステートメントにも当てはまります。私の経験では、IntelliJの自動フォーマットの適用方法はより柔軟です。 IntelliJは行リターンを削除または追加する可能性が低く、そこに配置すると、そこに配置するつもりであると想定します。 IntelliJは、タブスペースを喜んで調整します。


IntelliJは、これの一部を行うように構成することもできます。 [設定]-> [コードスタイル]-> [Java]の[ラッピングとブレース]タブで、[チェーンメソッド呼び出し]を[常にラップする]に設定できます。

自動フォーマットの前に

// Mulit-Line Statement
List<String> strings = Arrays.stream(ppl).filter((x) -> { return x.contains("(M)"); }).collect(Collectors.toList());

// Single-Line Statement
List<String> strings = Arrays.stream(ppl).map((x) -> x.toUpperCase()).filter((x) -> x.contains("(M)")).collect(Collectors.toList());

自動フォーマット後

// Mulit-Line Statement
List<String> strings = Arrays.stream(ppl)
        .filter((x) -> {
            return x.contains("(M)");
        })
        .collect(Collectors.toList());

// Single-Line Statement
List<String> strings = Arrays.stream(ppl)
        .map((x) -> x.toUpperCase())
        .filter((x) -> x.contains("(M)"))
        .collect(Collectors.toList());
24
Mike Rylander

Eclipseで、単一行ステートメントの場合:

プロジェクトまたはグローバル設定で、Java -> Code Style -> Formatter -> Edit -> Line Wrapping -> Function Calls -> Qualified Invocations、 セットする Wrap all elements, except first if not necessaryおよびティックForce split, even if line shorter than maximum line width

52
Arend

Eclipse(Mars)には、ラムダ式フォーマッターのオプションがあります。

Window > Preferences > Java > Code Style > Formatterに移動します

enter image description here

Editボタンをクリックし、Bracesタグに移動して、Lambda BodyNext Line Indentedに設定します

enter image description here

別のオプションは、これらのプロパティをプロジェクト設定に更新することです。 (yourWorkspace > yourProject > .settings > org.Eclipse.jdt.core.prefs

org.Eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.Eclipse.jdt.core.formatter.brace_position_for_lambda_body=next_line_shifted
19
Diego D

関数の後に空のコメント「//」を追加して、単一行ステートメントをフォーマットします。

List<Integer> list = Arrays.stream(x) //
                           .filter((n) -> n % 2 == 0) //
                           .map((n) -> n * 4) //
                           .boxed() //
                           .collect(Collectors.toList());
14
Saljack

現在、この質問は古く、残念ながら、Eclipseフォーマッターのデフォルト構成は、機能的なコードを読みやすい方法で作成するのにユーザーフレンドリーではありません。

私は他のすべての回答で言及されていることをすべて試しましたが、ほとんどのユースケースには誰も適していません。
一部の人にとっては問題ないかもしれませんが、他の人にとっては不快です。

ほとんどの場合、私に合った方法を見つけました。
他の人を助けることができると考えて共有します。

私の方法にはトレードオフがあることに注意してください。各修飾された呼び出しは常に別個の行にあることを受け入れます。
これは、おそらくフォーマッタ構成にないオプションです。デフォルトで1呼び出しを使用する代わりに、行をラップする呼び出しに関してしきい値を示します。

かなり正確に処理するための2つの結合ツールを次に示します。

  • ほとんどの場合のEclipseフォーマッター構成のカスタマイズ

  • コーナーケース用の//@formatter:off ... //@formatter:onを使用したコードテンプレートの作成。


Eclipseフォーマッター構成のカスタマイズ
変更する値は、キャプチャでは赤で囲まれています。

ステップ1)独自のJava Code Style Formatterを作成

Preferencesメニューおよびツリーで、Java -> Code Style -> Formatterに移動します。
「新規」をクリックして、新しいProfileを作成します(「Java規約」で初期化します)。

Eclipse formatter

次の2つの手順は、カスタムフォーマッタプロファイルで実行する必要があります。

手順2)折り返された行のインデント構成を変更する

Identation configuration

この変更により、表ではなく空白を使用できます。
列のインデントオプションを使用して行折り返しポリシーを構成するとき、次のステップで問題になります。
実際に不快なスペースを作成することを避けます。

ステップ3)ラップされた行のデフォルトのインデントと修飾された呼び出しの行ラッピングポリシーを変更する

Wrapped line size


質問のコードを使用したテストの書式設定を次に示します。

フォーマットする前に:

void multiLineStatements() {
    String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des (M)", "Rick (M)" };
    List<String> strings = Arrays.stream(ppl).filter((x) ->
    {
        return x.contains("(M)");
    }).collect(Collectors.toList());
    strings.stream().forEach(System.out::println);
}

void singleLineStatements() {
    String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des(M)", "Rick (M)" };
    List<String> strings = Arrays.stream(ppl).map((x) -> x.toUpperCase())
            .filter((x) -> x.contains("(M)")).collect(Collectors.toList());
    strings.stream().forEach(System.out::println);
}

フォーマット後:

void multiLineStatements() {
    String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des (M)", "Rick (M)" };
    List<String> strings = Arrays.stream(ppl)
                                 .filter((x) -> {
                                     return x.contains("(M)");
                                 })
                                 .collect(Collectors.toList());
    strings.stream()
           .forEach(System.out::println);
}

void singleLineStatements() {
    String[] ppl = new String[] { "Karen (F)", "Kevin (M)", "Lee (M)", "Joan (F)", "Des(M)", "Rick (M)" };
    List<String> strings = Arrays.stream(ppl)
                                 .map((x) -> x.toUpperCase())
                                 .filter((x) -> x.contains("(M)"))
                                 .collect(Collectors.toList());
    strings.stream()
           .forEach(System.out::println);
}

コーナーケースの場合、//@formatter:off ... //@formatter:onを使用してコードテンプレートを作成します。

手動またはコピー&ペースト//@formatter:onおよび//@formatter:offは、めったに書きませんので問題ありません。

ステップ1)Java Editor template

Preferencesメニューおよびツリーで、Java ->Editor -> Templateに移動します。
enter image description here

ステップ2)選択したコードのフォーマットを無効にするテンプレートを作成します

Template Formatter off on

これでテストできます。
フォーマットを無効にする行を選択します。
ここでctrl+spaceを2回入力します(1つ目は「Java提案」、2つ目は「テンプレート提案」です)。
次のようなものが表示されます:

template proposal

スクリーンショットのようにfmtテンプレートを選択し、[Enter]をクリックします。できた!

result after template application

12
davidxxx

理想的ではありませんが、少し密度の高いセクションだけでフォーマッタをオフにすることができます。例えば

  //@formatter:off
  int sum = Arrays.stream(x)
        .map((n) -> n * 5)
        .filter((n) -> {
            System.out.println("Filtering: " + n);
            return n % 3 != 0;
        })
        .reduce(0, Integer::sum);
  //@formatter:on

[ウィンドウ]> [設定]> Java>コードスタイル>フォーマッター)に移動します。[編集...]ボタンをクリックし、[タグのオン/オフ]タブに移動してタグを有効にします。

7
throp