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.)
EDIT: Ближайшим, что я мог получить, был с IntelliJ IDEA 13 Community Edition (читай: бесплатное издание: 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, похоже, не дает возможности поместить открытую скобку лямбды в новую строку, в противном случае это довольно разумный способ форматирования, поэтому я буду отмечать это как принятое.
Ответы
Ответ 1
Возможно, вам будет полезен 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" на вкладке "Обертка и привязки" вы можете установить "цепные вызовы методов" на "wrap always".
Перед автоматическим форматированием
// 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
В 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
.
Ответ 3
Eclipse (Mars) имеет возможность форматирования лямбда-выражений.
Перейдите к Window > Preferences > Java > Code Style > Formatter
![введите описание изображения здесь]()
Нажмите кнопку Edit
, перейдите к тегу Braces
и установите для параметра Lambda Body
значение Next 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
Ответ 4
Я форматирую однострочный оператор, добавляя пустой комментарий "//" после функций.
List<Integer> list = Arrays.stream(x) //
.filter((n) -> n % 2 == 0) //
.map((n) -> n * 4) //
.boxed() //
.collect(Collectors.toList());
Ответ 5
Не идеально, но вы можете отключить форматировщик только для тех участков, которые немного плотные. Например
//@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" > "Стиль кода" > "Форматирование". Нажмите кнопку "Изменить...", перейдите на вкладку "Выкл./Вкл." И включите теги.
Ответ 6
Этот вопрос сейчас старый и, к сожалению, по умолчанию конфигурация форматирования Eclipse по-прежнему не является удобной для написания функционального кода читаемым способом.
Я пробовал все вещи, упомянутые во всех других ответах, и никто не подходит для большинства случаев использования.
Это может быть хорошо для некоторых, но неприятно для других.
Я нашел способ, который подходит для меня большую часть времени.
Я разделяю это, думая, что это может помочь другим.
Обратите внимание, что мой способ имеет компромисс: принятие того, что каждый квалифицированный вызов всегда находится на отдельной строке.
Возможно, это недостающий параметр в конфигурации форматирования: указание порога в терминах invocations для обертывания строки вместо использования 1
вызова по умолчанию.
Вот мои 2 комбинированных инструмента для правильной обработки:
Настройка конфигурации форматирования 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) Создайте шаблон, чтобы отключить форматирование для выбранного кода
![Formatter Formatter off on]()
Теперь вы можете протестировать его.
Выберите строки, которые вы хотите отключить форматирование.
Теперь дважды введите ctrl+space
(первый из них - "предложения Java", а второй - "предложения шаблона" ).
Вы должны получить что-то вроде:
![предложение шаблона]()
Выберите шаблон fmt
, как на скриншоте, и нажмите "Enter".
Готово!
![результат после применения шаблона]()