Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Supplier<Optional<Article>>, а не Supplier<Article>.куча статических импортов, без которых с использованием stream api код перестаёт нормально выглядеть (конструкции слишком громоздкие, взгляд начинает цепляться за всякие Collectors.toList())
— отсутствие синтаксического сахара для apply приводит к более громоздким конструкциям,
getFirstJavaArticle().orElseGet(this::fetchLatestArticle)
getFirstJavaArticle().orElseGet(() -> fetchLatestArticle().get()) или getFirstJavaArticle().orElseGet(() -> fetchLatestArticle().orElse(null)) или ещё что-нибудь. Спецификация обработки ошибки может быть разной, и надо её явно указать.basedOnTag("Java"). Это бы позволило писать код, где уже непонятно, что перед нами — объект или метод (в данном случае basedOnTag — объект). Ну и плюс та же проблема с пространствами имён: в текущем классе может быть метод с именем basedOnTag. Может, мы хотим его вызвать?foldR, foldL, насколько я понимаю, антипараллельны. Концепция стримов как раз была в том, чтобы ограничиться операциями, которые нормально параллелятся. По этой же причине zip убрали. Можно, кстати, пример кода, когда с foldR/foldL всё красиво, а со stream api плохо?Да, они не могут выполняться параллельно, т. к. протаскивают состояния аккумулятора.
Кажется, понял, что вы имели в виду про apply. Java хранит ценное качество, что для понимания написанного требуется довольно узкий контекст. Благодаря этому тут не так много синтаксического сахара, как в других языках. Если перед круглыми скобками стоит идентификатор, это значит, что идентификатор — метод, а не десяток разных вещей в зависимости от контекста, как в некоторых других языках. Это очень хорошая фича, чтобы от неё взять и отказаться. Поэтому и нельзя написать basedOnTag(«Java»). Это бы позволило писать код, где уже непонятно, что перед нами — объект или метод (в данном случае basedOnTag — объект). Ну и плюс та же проблема с пространствами имён: в текущем классе может быть метод с именем basedOnTag. Может, мы хотим его вызвать?Да, это и плюс (с точки зрения понимания человеком, удобства разбора и анализа), и минус (больше синтаксического шума, меньше гибкость языка).
в java требует использования отдельных контейнеров (например, Map<K, V>.Entry). Или, например, более удобное преобразование Map[K, V] <-> List[(K, V)]
public List<Sequence> calculate(Map<String, List<ChipSeqPeak>> chromosomeToPeaks, GenomeDatabase db, int minLength) {
return EntryStream.of(chromosomeToPeaks)
.mapKeys( chr -> db.fetchSequence(chr) )
.flatMapValues( List::stream )
.mapKeyValue( (sequence, peak) -> peak.getSequenceRegion(sequence, minLength))
.toList();
}Если смотреть дальше, то можно уйти в сторону языков типа smalltalk, ruby, python, где этот контекст не выводится статически (во время компиляции), но разрешается во время исполнения.
Приятнее, чем было бы на голых стримах.Я видел ваш пост про streamex, выглядит куда более удобоваримо, нежели голые стримы.
Ну вот в том-то и дело, что у Java свой путь и своя философия, и статическое разрешение — часть её. Зачем создавать ещё один smalltalk или ruby, когда оно уже есть?Незачем. Никто и не агитирует, вроде.
List<T> list = toList(); IntStreamEx.range(list.size()).map(i -> list.get(list.size()-1-i)).foldLeft(...)private void sleep() {
try { Thread.sleep(10); } catch(InterruptedException e) {}
}
@Benchmark
public void foldLeftSeq(Blackhole bh) {
bh.consume(IntStreamEx.range(0,10).boxed().map(x -> {sleep();return x;})
.foldLeft(0, (a, b) -> {sleep();return a+b;}));
}
@Benchmark
public void foldLeftPar(Blackhole bh) {
bh.consume(IntStreamEx.range(0,10).parallel().boxed().map(x -> {sleep();return x;})
.foldLeft(0, (a, b) -> {sleep();return a+b;}));
}Benchmark Mode Cnt Score Error Units
FoldLeft.foldLeftPar avgt 20 126046361,977 ± 2005404,512 ns/op
FoldLeft.foldLeftSeq avgt 20 199882975,012 ± 16028,386 ns/oplist.foldRight("X")((a,b) => a + b)
list.reverse.foldLeft("X")((b,a) => a + b)Довольно круто, правда?
orElseGet
for (i <- 1 to n; j <- 1 to n if i <= j) yield (i, j)
// или так:
(1 to n).flatMap({ i => (1 to n).filter(i <= _).map({ j => (i, j) }) })
Новый уровень абстракции
Довольно круто, правда?
основная проблема обертки, как и в Scala, что Optional[Integer] не является Integer
SomeType? же в этом плане не лучше null с аннотациями.fun foo(s: String)
val s: String?
//вот это не скомпилируется
foo(s)
//а вот это уже скомпилируется
if (s != null)
foo(s)
fun doSomething(param:String?);
val s : String = "aaa";
doSomething(s);
open class Class1 {
open fun doSomething():String?;
}
open class Class2 : Class1() {
override open fun doSomething():String;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}public Optional<String> foo(); //может вернуть null, вместо empty()
public String bar(); //может вернуть null
В-третьих, Optional собственно не решает проблему null в Java. Он не гарантирует, что само возвращаемое значение Optional не будет null, равно как и что в коде с Optional возвращаемый не-Optional объект будет иметь ненулевое значение.Optional.get() всегда вернет не-null или кинет исключение.
// мне нравятся Optinal и теперь я буду их везде использовать
public Optional<String> getMyValue();
// а это мой старый код, который используется в куче мест и мне лень все это переписывать. Может ли он возвращать nullable, я уже и забыл.
public String getMyAnotherValue();
// а это код Васи, который поклялся, что тоже будет везде использовать Optional, но почему-то здесь иногда возвращает null.
public String getHisValue();
class MyBean {
// надо optional поле
private Optional<String> value;
// это сгенерит любая IDE
public Optional<String> getValue() {return value;}
public void setValue(Optional<String> value) {this.value = value;}
}
// где-то в коде
MyBean b = new MyBean();
// так можно, компилятор не матюгнется
b.setValue(null);
b.getValue().orElse(""); // NPE
// теперь сделаем все корректно:
class MyBean {
private String value; // чтобы bean был Serializable поля не должны быть Optional
// для каждого поля надо доработать аксессоры ручками
public Optional<String> getValue() {return Optional.ofNullable(value);}
public void setValue(Optional<String> value) {
if (value == null) this.value = null; // можно кинуть NPE в этом случае
this.value = value.orElse(null);
}
}
class MyBean {
private String value;
public Optional<String> getValueSafe() { return Optional.ofNullable(value); }
public String getValue() { return this.value; }
public void setValue(String value) {
this.value = value;
}
}
class MyBean {
@Nullable
private String value;
// а это сгенерит умная IDE
@Nullable
public String getValue() {return value;}
public void setValue(@Nullable value) {this.value = value;}
}
Java 8: Овладейте новым уровнем абстракции