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

时间:2014-07-09 09:28:23

标签: java eclipse lambda java-8 java-stream

我想用lambda缩进实现的目的如下:

多行声明:

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之下,并且根本没有空格。如果我可以在缩进的新行中启动lambda,那么我会更喜欢它,以便.filter(调用将在.collect(调用之上。但是,使用标准Java-8 Eclipse Formatter可以自定义的唯一内容是lambda主体开头的大括号,但事先没有()括号,也没有缩进。

在单行调用的情况下,它只使用基本的换行并使其成为链式混乱。我不认为我需要解释为什么之后难以解密。

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



编辑:我能得到的最接近的是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);    

它还允许“对齐”链式方法调用,如下所示:

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

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

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

<?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似乎没有提供一种方法将lambda的左括号放在一个新行中,否则它是一种相当合理的格式化方式,所以我会将其标记为已接受。

9 个答案:

答案 0 :(得分:49)

在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

答案 1 :(得分:25)

开箱即用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也可以配置为你做一些这样的事情。在&#34;设置&#34; - &GT; &#34;代码风格&#34; - &GT; &#34; java&#34;,在&#34; Wrapping and Braces&#34;选项卡,您可以设置&#34;链式方法调用&#34; to&#34;总是&#34;。

自动格式化之前

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

答案 2 :(得分:19)

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

转到Window > Preferences > Java > Code Style > Formatter

enter image description here

点击Edit按钮,转到Braces标记,然后将Lambda Body设置为Next 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

答案 3 :(得分:14)

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

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

答案 4 :(得分:10)

现在这个问题已经过时了,遗憾的是,Eclipse格式化程序的默认配置对于以可读方式编写功能代码仍然不是用户友好的。

我尝试了所有其他答案中提到的所有内容,并且没有人适合大多数用例 对某些人来说可能没什么问题,但对其他人来说却不愉快。

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

请注意,我的方式有一个权衡:接受每个合格的调用总是在不同的行上 它可能是格式化程序配置中缺少的选项:默认情况下,在调用包装行而不是使用1调用时指示阈值。

以下是我的两个组合工具,可以正确处理它:

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

  • 为角落案例创建一个//@formatter:off ... //@formatter:on的代码模板。

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

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

Preferences菜单,然后在树中转到Java -> Code Style -> Formatter 点击&#34;新&#34;创建一个新的Profile(使用&#34初始化它; Java约定&#34;)。

Eclipse formatter

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

步骤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编辑器模板

Preferences菜单,然后在树中转到Java ->Editor -> Template enter image description here

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

Template Formatter off on

您现在可以测试它 选择要禁用格式的行 现在输入ctrl+space两次(第一个是&#34; Java提案&#34;第二个是&#34;模板提案&#34;)。 你应该得到类似的东西:

template proposal

在屏幕截图中选择fmt模板,然后点击&#34;输入&#34;。 完成!

result after template application

答案 5 :(得分:7)

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

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

转到&#34;窗口&gt;偏好&gt; Java&gt;代码风格&gt;格式化&#34 ;.点击&#34;编辑...&#34;按钮,转到&#34;关/开标签&#34;选项卡并启用标记。

答案 6 :(得分:2)

最适合我的选项是在“首选项”中“格式化程序”的“换行”部分中选中Never join already wrapped lines选项。

答案 7 :(得分:1)

如果您还没有自定义的Eclipse格式化程序:

Eclipse首选项 Java>代码样式>格式器 新 输入名字 点击确定 控制换行符

编辑个人资料 换行标签 选中“从不加入已包装的行”

它最终会像这样

    String phrase = employeeList
            .stream()
            .filter(p -> p.getAge() >= 33)
            .map(p -> p.getFirstName())
            .collect(Collectors.joining(" and ", "In Germany ", " are of legal age."));

需要输入every。从下一行开始

信用-https://www.selikoff.net/2017/07/02/eclipse-and-line-wrapping/

答案 8 :(得分:-1)

Eclipse的最新版本具有内置的格式化程序java 8 formatto goto

Preferences -> Java -> Code Style -> Formatter -> Active profile

and Select Eclipse 2.1[built-in] profile