Встроенная функция, заполняющая массив

#java #arrays #lambda

Вопрос:

Есть ли какой-нибудь способ объявить и заполнить массив в Java с помощью встроенной функции / лямбда, как показано ниже?

 final int NUM_NAMES = 10;
String names = () -> {
    ArrayList<String> names = new ArrayList();
    for (int i = 0; i < NUM_NAMES; i  ) {
        names.add("Name "   i);
    }
    return names.toArray();
};
 

Комментарии:

1. Вы можете сделать что-то подобное, если целевой / объявленный тип лямбда-выражения является функциональным интерфейсом (а не строкой, как у вас). Чего именно вы пытаетесь достичь?

2. IntStream.range(0, NUM_NAMES).mapToObj(i -> "Name " i).toArray(String[]::new) .

Ответ №1:

Вы могли бы использовать следующее:

 List<String> names = IntStream.range(0, 10)
    .boxed()
    .map(i -> String.format("Name %d", i))
    .collect(Collectors.toList())
 

Надеюсь, синтаксис там в порядке, но вы поняли идею.

Комментарии:

1. Не нужно этого делать boxed() , просто делай mapToObj(...) .

2. @AndyTurner Тогда, однако, в выражении была бы автоматическая String.format("Name %d", i) блокировка, которую этот подход обходит. Я думаю, это компромисс.

3. @Izruo на самом деле речь идет не о боксе, а скорее о том, что не нужно явно вставлять бокс. (Но вы можете избежать бокса, офк, просто выполнив прямую конкатенацию "name " i ).

Ответ №2:

Технически вы можете сделать это встроенным, но синтаксис довольно подробный:

 String[] names = ((Supplier<String[]>)() -> {
  ArrayList<String> namesList = new ArrayList<>();
  for (int i = 0; i < NUM_NAMES; i  ) {
    namesList.add("Name "   i);
  }
  return namesList.toArray(new String[0]);
}).get();
 

поэтому я бы не рекомендовал это. Вам нужно будет указать тип лямбда-выражения, привести его к этому типу, а затем поместить все приведенное выражение в скобки, чтобы вы могли вызвать get , чтобы получить созданный массив.

Более кратким способом инициализации встроенных массивов был бы вспомогательный метод, подобный этому (он вдохновлен конструкторами массивов Kotlin):

 public static <T> T[] buildArray(T[] arr, IntFunction<T> elementFunction) {
    for (int i = 0 ; i < arr.length ; i  ) {
      arr[i] = elementFunction.apply(i);
    }
    return arr;
}
 

Во втором параметре вы указываете, какой элемент вы хотите для каждого индекса:

 String[] names = buildArray(new String[NUM_NAMES], i -> "Name "   i);
 

Комментарии:

1. Ваш buildArray метод — это то, как Arrays.setAll он должен был быть реализован.

Ответ №3:

Возможно, самый короткий способ — использовать Arrays.setAll, который можно использовать для установки значений в массивах любого типа, а также генератор индексных значений для определения каждого индексированного значения:

 String[] names = new String[NUM_NAMES];
Arrays.setAll(names, i -> "Name "   i);
 

К сожалению Arrays.setAll , не возвращает массив, поэтому вы не можете поместить все объявление names в одну строку.