Конечно, мы все любим сливочное, функциональное совершенство, которое сочится из Java 8. И я, конечно, не императивист, как те, кто в этом видео Java .
Но одна вещь беспокоит меня.
Это незначительно. Вряд ли стоит упоминать, едва неудобства . Но … раздражает.
Меня беспокоит, насколько легко читать потоковую обработку.
Давайте вытащим случайный репозиторий Java из GitHub — Apache Flink — и возьмем из него пример совершенно незаметной потоковой обработки. В FlinkPreparingTableBase
мы находим:
Джава
1
for (Set<String> keys : uniqueKeys) {
2
boolean allUniqueKeysExists = keys.stream()
3
.allMatch(f -> rowType.getField(f, false, false) != null);
4
...
6
}
(Код упрощен для целей представления.) Вопрос в том, какой тип параметра f
?
И ответ прост: это строка . Откуда нам знать? Поскольку поток обрабатывает над клавишами и клавишами является набором из строки . Все объявленные две строки раньше; в нескольких шагах.
Хорошо. Может быть немного удивительно, что параметр вызывается f
(для «поля»), а не k
(для «ключа»), но в порядке.
Теперь давайте посмотрим на другой класс, Флинк PlannerQueryOperation
:
Джава
xxxxxxxxxx
1
public PlannerQueryOperation() {
2
DataType[] fieldTypes = rowType.getFieldList()
3
.stream()
4
.map(field ->
5
LogicalTypeDataTypeConverter.fromLogicalTypeToDataType(
6
FlinkTypeFactory.toLogicalType(field.getType())))
7
.toArray(DataType[]::new);
8
...
10
}
11
Теперь похожий вопрос: какой тип параметра field
?
Во-первых, по крайней мере, имя прописано: «поле», а не «f». Но это все еще строка ?
Ну, field
это элемент того, что getFieldList()
возвращается. И мы отмечаем, что переменная rowType
появляется в обоих фрагментах (оба из которых оказываются типа RelDataType
). В первом фрагменте мы вызываем rowType.getField()
с String
параметром, так что, может быть, второй фрагмент rowType.getFieldList()
также возвращает коллекцию того, String
что мы можем затем обработать потоком?
Но затем мы заглядываем дальше в ручей и находим field.getType()
.
Так что field
, что бы то ни было , это не строка .
Это проблема.
Мы не знаем тип field
и не можем увидеть его случайным движением глаз, как мы это делали в первом примере.
Вместо этого мы должны найти RelDataType
и проверить, какой тип getFieldList()
возвращает.
И все это потому, что наши Glorious Java Overlords сделали необязательным явное указание типов параметров при потоковой обработке.
Это то, что раздражает меня.
Почему они не сделали это обязательным?
Мы можем решить проблему, явно указав тип, например:
xxxxxxxxxx
1
public PlannerQueryOperation() {
2
DataType[] fieldTypes = rowType.getFieldList()
3
.stream()
4
.map((RelDataTypeField field) ->
5
LogicalTypeDataTypeConverter.fromLogicalTypeToDataType(
6
FlinkTypeFactory.toLogicalType(field.getType())))
7
.toArray(DataType[]::new);
8
...
10
}
Итак, является ли этот третий фрагмент более «легким для чтения», чем второй?
Что мы имеем в виду, говоря, что код «легко читается?»
Кто-то скажет, что второе легче читать, потому что в нем пропущены несущественные типы и вонючие скобки таблички котла.
Кто-то скажет, что третий легче читать, потому что он делает типы явными.
Я знаю, что я предпочитаю.
Я просто хочу, чтобы боги Java не дали нам выбора.