Java 8:使用换行符和缩进格式化 lambda

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24649971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 13:45:26  来源:igfitidea点击:

Java 8: Formatting lambda with newlines and indentation

javaeclipselambdajava-8java-stream

提问by EpicPandaForce

What I would like to achieve with lambda indentation is the following:

我想用 lambda 缩进实现以下目标:

Multi-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);

Single-line statement:

单行语句:

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



Currently, Eclipse is auto-formatting to the following:



目前,Eclipse 正在自动格式化为以下内容:

Multi-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);

Single-line statement:

单行语句:

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);

And I find this really messy, because of how the collectcall is directly underneath the returnand there's no space inbetween at all. I would prefer it if I could start the lambda in a new line indented, and so that the .filter(call would be right above the .collect(call. However, the only thing that can be customized with standard Java-8 Eclipse Formatter is the brace at the start of the lambda body, but nothing for the ()brackets beforehand, nor the indentation.

而且我觉得这真的很乱,因为collect调用直接在 下方,return而且中间根本没有空间。如果我可以在缩进的新行中启动 lambda,我会更喜欢它,这样.filter(调用就在调用的正上方.collect(。但是,唯一可以使用标准 Java-8 Eclipse Formatter 自定义的是 lambda 主体开头的大括号,但()事先没有任何用于括号的内容,也没有缩进。

And in the case of single-line calls, it just uses the basic line-wrap and makes it be a chained mess. I don't think I need to explain why this is hard to decrypt afterwards.

在单行调用的情况下,它只使用基本的换行并使其成为一团糟。我认为我不需要解释为什么这之后很难解密。

Is there any way to somehow customize the formatting more and achieve the first formatting type in Eclipse? (Or, optionally, in another IDE like IntelliJ IDEA.)

有没有办法以某种方式更多地自定义格式并在 Eclipse 中实现第一种格式类型?(或者,可选地,在另一个 IDE 中,例如 IntelliJ IDEA。)



EDIT: The closest I could get was with IntelliJ IDEA 13 Community Edition (read: free edition :P) which was the following (defined by continuous indentation which in this case is 8):



编辑:我能得到的最接近的是 IntelliJ IDEA 13 社区版(阅读:免费版: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);    

It also allows to "align" the chained method invocation like this:

它还允许像这样“对齐”链式方法调用:

    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);
}

I personally find that while it makes more sense, the second version pushes it far too away, so I prefer the first one.

我个人觉得虽然它更有意义,但第二个版本把它推得太远了,所以我更喜欢第一个。

The setup responsible for the first setup is the following:

负责第一次设置的设置如下:

<?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>

I tried to make sure everything is reasonable, but I might have messed something up, so it might need minor adjustments.

我试图确保一切都是合理的,但我可能搞砸了一些事情,所以它可能需要一些小的调整。

If you're Hungarian like me and you're using a Hungarian layout, then this keymap might be of use to you, so that you don't end up not being able to use AltGR+F, AltGR+G, AltGR+B, AltGR+N and AltGR+M (which correspond to Ctrl+Alt).

如果你像我一样是匈牙利人并且你使用的是匈牙利语布局,那么这个键盘映射可能对你有用,这样你就不会最终无法使用 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>

While IntelliJ doesn't seem to provide a way to put the opening brace of the lambda in a new line, otherwise it's a fairly reasonable way of formatting, so I'll mark this as accepted.

虽然 IntelliJ 似乎没有提供将 lambda 的左大括号放在新行中的方法,但它是一种相当合理的格式化方式,因此我将其标记为已接受。

采纳答案by Mike Rylander

Out of the box IntelliJ 13 will probably work for you.

开箱即用的 IntelliJ 13 可能适合您。

If I write it this way:

如果我这样写:

// 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);

And then apply the auto formatter (no changes):

然后应用自动格式化程序(无变化):

// 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);

The same is true for your single line statement. It has been my experience that IntelliJ is more flexible in how its auto formatting is applied. IntelliJ is less likely to remove or add line returns, if you put it there then it assumes you meant to put it there. IntelliJ will happily adjust your tab-space for you.

您的单行语句也是如此。根据我的经验,IntelliJ 在如何应用其自动格式化方面更加灵活。IntelliJ 不太可能删除或添加行返回,如果你把它放在那里,那么它假设你打算把它放在那里。IntelliJ 会很乐意为您调整标签空间。



IntelliJ can also be configured to do some of this for you. Under "settings" -> "code style" -> "java", in the "Wrapping and Braces" tab you can set "chain method calls" to "wrap always".

IntelliJ 还可以配置为为您执行其中的一些操作。在“设置”->“代码样式”->“java”下,在“包装和大括号”选项卡中,您可以将“链方法调用”设置为“始终包装”。

Before Auto-Formatting

自动格式化之前

// 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());

After Auto-Formatting

自动格式化后

// 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());

回答by throp

Not ideal, but you could turn the formatter off for just those sections that are a little dense. For example

不理想,但您可以只为那些有点密集的部分关闭格式化程序。例如

  //@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

Go to "Window > Preferences > Java > Code Style > Formatter". Click the "Edit..." button, go to the "Off/On Tags" tab and enable the tags.

转到“窗口 > 首选项 > Java > 代码样式 > 格式化程序”。单击“编辑...”按钮,转到“关闭/打开标签”选项卡并启用标签。

回答by Diego D

Eclipse (Mars) has an option for lambda expressions formatter.

Eclipse (Mars) 有一个用于 lambda 表达式格式化程序的选项。

Go to Window > Preferences > Java > Code Style > Formatter

Window > Preferences > Java > Code Style > Formatter

enter image description here

在此处输入图片说明

Click the Editbutton, go to the BracesTag and set the Lambda Bodyto Next Line Indented

单击Edit按钮,转到Braces标签并将其设置Lambda BodyNext Line Indented

enter image description here

在此处输入图片说明

Another option is update these properties into your project settings. (yourWorkspace > yourProject > .settings > org.eclipse.jdt.core.prefs)

另一种选择是将这些属性更新到您的项目设置中。( 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

回答by Arend

In Eclipse, for the single-line statements:

在 Eclipse 中,对于单行语句:

In your project or global preferences, go to Java -> Code Style -> Formatter -> Edit -> Line Wrapping -> Function Calls -> Qualified Invocations, set Wrap all elements, except first if not necessaryand tick Force split, even if line shorter than maximum line width.

在您的项目或全局首选项中,转到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

回答by SalHyman

I format single-line statement by adding empty comment "//" after functions.

我通过在函数后添加空注释“//”来格式化单行语句。

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

回答by davidxxx

This question is now old and unfortunately, the default configuration of the Eclipse formatter remains still not user-friendly to write functional code in a readable way.

这个问题现在很老了,不幸的是,Eclipse 格式化程序的默认配置仍然不是用户友好的,无法以可读的方式编写功能代码。

I tried all things mentioned in all other answers and no one suits for most of use cases.
It may be fine for some but unpleasant for others.

我尝试了所有其他答案中提到的所有内容,但没有一个适合大多数用例。
对某些人来说可能很好,但对其他人来说可能不愉快。

I found a way that suits for me the most of the time.
I share it by thinking that it could help others.

我找到了一种最适合我的方式。
我分享它,认为它可以帮助他人。

Note that my way has a trade-off : accepting that each qualified invocation be always on a distinct line.
It is maybe the missing option in the formatter configuration : indicating the threshold in terms of invocations to wrap the line instead of using 1invocation by default.

请注意,我的方式有一个权衡:接受每个合格的调用始终在不同的行上。
这可能是格式化程序配置中缺少的选项:指示在调用方面的阈值以换行而不是1默认使用调用。

Here are my 2 combined tools to handle it rather correctly :

这是我的 2 个组合工具来正确处理它:

  • Customizing Eclipse formatter configuration for most of cases

  • Creating a code template with //@formatter:off ... //@formatter:onfor corner cases.

  • 在大多数情况下自定义 Eclipse 格式化程序配置

  • //@formatter:off ... //@formatter:on为极端情况创建代码模板 。



Customizing Eclipse formatter configuration
The value to change are surrounded in red in the capture.

自定义 Eclipse 格式化程序配置
要更改的值在捕获中以红色包围。

Step 1) Create your own Java Code Style Formatter

步骤 1) 创建您自己的 Java 代码样式格式化程序

Preferencesmenu and in the tree, go to Java -> Code Style -> Formatter.
Click on "New" to create a new Profile(initialize it with "Java conventions").

Preferences菜单并在树中,转到 Java -> Code Style -> Formatter
单击“新建”以创建一个新的Profile(使用“Java 约定”对其进行初始化)。

Eclipse formatter

Eclipse 格式化程序

The two next steps have to be performed in your custom formatter profile.

接下来的两个步骤必须在您的自定义格式化程序配置文件中执行。

Step 2) Change the indentation configuration for wrapped lines

步骤 2) 更改换行的缩进配置

Identation configuration

标识配置

The modification allows to use whitespaces instead of tabulations.
It will matter in the next step as we configure the line wrapping policy with the column indentation option.
It will avoid indeed creates unpleasant spaces.

修改允许使用空格而不是表格。
当我们使用列缩进选项配置换行策略时,下一步将很重要。
它将避免确实产生令人不快的空间。

Step 3) Change the default indentation for wrapped lines and the line wrapping policy for qualified invocation

步骤 3) 更改换行的默认缩进和限定调用的换行策略

Wrapped line size

绕线尺寸



Here is a test formatting with code of the question.

这是带有问题代码的测试格式。

Before formatting :

格式化前:

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);
}

After formatting :

格式化后:

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);
}


Creating code templates with //@formatter:off ... //@formatter:onfor corner cases.

//@formatter:off ... //@formatter:on为极端情况创建代码模板 。

Writing manually or copy-paste //@formatter:onand //@formatter:offis fine as you write it rarely.
But if you have to write it several times by week or even worse by day, a more automatic way is welcome.

手动编写或复制粘贴//@formatter:on//@formatter:off是好的,你写的很少。
但是,如果您必须每周多次甚至每天更糟地编写它,则欢迎使用更自动的方式。

Step 1) Go to Java Editor template

步骤 1) 转到 Java 编辑器模板

Preferencesmenu and in the tree, go to Java ->Editor -> Template.
enter image description here

Preferences菜单并在树中,转到 Java ->Editor -> Template
在此处输入图片说明

Step 2) Create template to disable formatting for selected code

步骤 2) 创建模板以禁用所选代码的格式设置

Template Formatter off on

模板格式化程序关闭

You can now test it.
Select lines which you want to disable the formatting.
Now enter ctrl+spacetwice (first one is "Java proposals" and the second one is "template proposals").
You should get something like :

您现在可以对其进行测试。
选择要禁用格式的行。
现在输入ctrl+space两次(第一个是“Java 建议”,第二个是“模板建议”)。
你应该得到类似的东西:

template proposal

模板提案

Select the fmttemplate as in the screenshot and click "Enter". Done!

选择fmt屏幕截图中的模板,然后单击“Enter”。完毕!

result after template application

模板应用后的结果