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


82

我想通过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中实现第一种格式类型?(或者,可选地,在另一个IntelliJ IDEA之类的IDE中。)



编辑:我能得到的最接近的是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的左大括号放在新行中的方法,否则它是一种相当合理的格式化方式,因此我将其标记为接受。


10
你不能用.filter(x -> x.contains("(M)"))吗?简单得多...如果您实际上是在谈论需要多个语句的地方,那么最好给出一个需要它的示例。
乔恩·斯基特

@JonSkeet我现在真的还没有想到一个真正的多行用例,但是我添加了这两种用例。
EpicPandaForce 2014年

2
坦白地说,有人在下面发布并删除了“ Netbeans 8.0”版本,这确实很接近事实,尽管Netbeans臭名昭著的是不允许正确地将语句的开头括号格式化为Allman样式。
EpicPandaForce 2014年

3
我猜当前的解决方案是启用“永不合并换行”并手动设置格式,但是与Ctrl+Alt+F您要自动格式化其他人的代码相比,这似乎有些乏味。
EpicPandaForce 2014年

由于某种原因,Eclipse在x不打开花括号并将其关闭的情况下就无法确定其类型,因此,为什么我首先使用语句而不是简单版本。
EpicPandaForce 2014年

Answers:


29

开箱即用的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());

问题是,它能够自动以这种方式格式化吗?如果自动格式化在按照我喜欢的样式设置代码的格式方面做得很好,则可以简化问题,这样任何代码甚至其他任何人的代码都更易于阅读。
EpicPandaForce 2014年

@Zhuinden我用一个示例对单行语句执行此操作的示例进行了更新。如图所示,它对于多行语句也有一定程度的作用。配置IntelliJ的自动格式化程序有很多选项,您可以对其进行优化以使其完全符合您的问题。
Mike Rylander 2014年

我根据上面粘贴的XML进行了设置,我猜我将在非Android平台上使用IntelliJ而不是Eclipse。谢谢。
EpicPandaForce 2014年

1
@EpicPandaForce为什么不将它也用于Android?
herman 2014年

从技术上来说,@ herman从那时起,我也开始使用Android版Android Studio。我不得不安装一些额外的RAM,但是公司已经有了一些空间,所以现在有了8 GB,Gradle在编译时不会冻结整个计算机:P
EpicPandaForce 2014年

59

在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


嘿,这似乎还可以,除了我被迫缩进了,或者使用默认的indindation或column或1。这没有任何意义。我的缩进根据当前情况有所不同。例如:最终List <DataRow>天= MappedSelect.query(“ gameDays”,DataRow.class).param(“ seasonId”,20142015).select(context); 对于以上内容,我希望接下来的2行在前一行的点上完全缩进。
Saravana Kumar M

1
几乎完美!:-)但是,有时它会根据我的喜好包装太多:lambda中的语句,例如,.filter(c -> c.getValue().equals(newValue))也将在.equals之前包装。如果这样的设置仅适用于与lambda相关的方法,那将是一个很好的选择。我看到这可能很难实现……
Dominic '18

24

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

Window > Preferences > Java > Code Style > Formatter

在此处输入图片说明

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

在此处输入图片说明

另一个选择是将这些属性更新为项目设置。(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

2
这似乎只对带括号的lambda有帮助。
尼克,

更新这些属性无济于事
Piotr Wittchen

19

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

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

我找到了最适合我的方式。
我以为它可以帮助其他人而分享它。

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

这是我的2种组合工具,可以相当正确地处理它:

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

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


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

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

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

Eclipse格式化程序

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

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

身份配置

修改允许使用空格而不是制表符。
下一步很重要,因为我们使用列缩进选项配置了换行策略。
它将避免确实造成不愉快的空间。

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

包线尺寸


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

格式化之前:

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
在此处输入图片说明

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

模板格式化程序关闭

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

模板提案

选择fmt屏幕快照中的模板,然后单击“ Enter”。做完了!

模板申请后的结果


16

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

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

3
简单有效。
史蒂夫

12
我认为这只是因为未设置IDE样式配置而对您的代码库造成干扰。对于第一次看您的代码库的人可能会造成混淆。
Marc Bouvier

9

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

  //@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>代码样式>格式化程序”。单击“编辑...”按钮,转到“关闭/打开标签”选项卡并启用标签。


3
这似乎是一种愚蠢但简单的选择,可以使我的格式正确无误
smc

2

对我有用的Never join already wrapped lines选项是在“首选项”中“格式化程序”的“换行”部分中打勾的选项。


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

需要输入每个。从下一行开始

积分-https: //www.selikoff.net/2017/07/02/eclipse-and-line-wrapping/


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.