Core-2: Streams & Optional Flashcards

1
Q

Что такое Optional?

A

Optional — это контейнер для объекта, который может содержать или не содержать значение null.
Основное примененение: возвращаемое значение метода, когда возвращаемое значение может отсутствовать (null).
Нужен для:
- предотвращения NullPointerException, избегая BoilepPlate
- указать пользователю, что здесь может быть null
Такая обёртка является удобным средством , т.к. имеет некоторые функции высшего порядка, избавляющие от добавления повторяющихся if null/notNull проверок:

Optional<String> optional = Optional.of("hello");

optional.isPresent(); // true
optional.ifPresent(s -> System.out.println(s.length())); // 5
optional.get(); // "hello"
optional.orElse("ops..."); // "hello"

Как правило используется в качестве возвращаемого значения метода и использовать его стоит там где есть вероятность отсутствия возвращаемого значения.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Главные методы Optional<T>

A
  • public static<T> Optional<T> empty() : Returns an empty Optional instance.
  • public static <T> Optional<T> of(T value) : Returns an Optional describing the given non-null value. Throws: NullPointerException – if value is null
  • public static <T> Optional<T> ofNullable(T value) : Returns an Optional describing the given value, if non-null, otherwise returns an empty Optional. Should only be used if NPE may be thrown.
  • public T get() : If a value is present, returns the value, otherwise throws NoSuchElementException. API Note:The preferred alternative to this method is
  • public boolean isPresent(): If a value is present, returns true, otherwise false.
  • public void ifPresent(Consumer<? super T> action) : If a value is present, performs the given action with the value, otherwise does nothing. Throws:
    NullPointerException – if value is present and the given action is null
  • public Optional<T> filter(Predicate<? super T> predicate) : If a value is present, and the value matches the given predicate, returns an Optional describing the value, otherwise returns an empty Optional. Throws: NullPointerException – if the predicate is null

- public <U> Optional<U> map(Function<? super T, ? extends U> mapper)

  • public <U> Optional<U> flatMap( Function<? super T, ? extends Optional<? extends U>> mapper) : Dealing with nested optionals is the most common case when we need to use flatMap instead of map
  • public T orElse(T other) : If a value is present, returns the value, otherwise returns other.

- public T orElseGet(Supplier<? extends T> supplier) : If a value is present, returns the value, otherwise returns other.

- public T orElseThrow() : If a value is present, returns the value, otherwise throws NoSuchElementException

SINCE JAVA 9:
- public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
- public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
- public Stream<T> stream()
-
SINCE JAVA 10:
- orElseThrow()
SINCE JAVA 11:
- public boolean isEmpty() If no value, returns true, otherwise false

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Что такое Stream? Какие типы операций у него бывают и в чем их логика?

A

Интерфейс java.util.Stream представляет собой обертку над источником данных, с помощью которой можно параллельно или последовательно обрабатывать эти данные в функциональном стиле, не меняя сам источник данных.

Операции над стримами бывают или промежуточными (intermediate) или конечными (terminal). Конечные операции возвращают результат определенного типа, а промежуточные операции возвращают тот же стрим. Таким образом вы можете строить цепочки из несколько операций над одним и тем же стримом.

У стрима может быть сколько угодно вызовов промежуточных операций и последним вызов конечной операции. При этом все промежуточные операции выполняются лениво и пока не будет вызвана конечная операция никаких действий на самом деле не происходит (похоже на создание объекта Thread или Runnable, без вызова start()).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Поддерживают ли стримы Ассоциативные массивы?

A

Ассоциативные массивы (maps), например, HashMap, не поддерживаются.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Можно ли переиспользовать Stream и могут ли они операции исполняться паралельно?

A

Потоки не могут быть использованы повторно. Как только была вызвана какая-нибудь конечная операция, поток закрывается.

Операции над стримами могут выполняться как последовательно, так и параллельно.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Чем лучше пользоваться при работе со стримами примитивов?

A

Кроме универсальных объектных существуют особые виды стримов для работы с примитивными типами данных int, long и double: IntStream, LongStream и DoubleStream. Эти примитивные стримы работают так же, как и обычные объектные, но со следующими отличиями:

используют специализированные лямбда-выражения, например, IntFunction или IntPredicate вместо Function и Predicate;
поддерживают дополнительные конечные операции sum(), average(), mapToObj().

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Какие существуют способы создания стрима?

A

1) Из коллекции:
~~~
Stream<String> fromCollection = Arrays.asList("x", "y", "z").stream();
~~~
2) Из набора значений:
~~~
Stream<String> fromValues = Stream.of("x", "y", "z");
~~~
3) Из массива:
~~~
- Stream<String> fromArray = Arrays.stream(new String[]{"x", "y", "z"});
~~~
4) Из файла (каждая строка в файле будет отдельным элементом в стриме):
~~~
Stream<String> fromFile = Files.lines(Paths.get("input.txt"));
~~~
5) Из строки:
~~~
IntStream fromString = "0123456789".chars();
~~~
6) С помощью Stream.builder():
~~~
Stream<String> fromBuilder = Stream.builder().add("z").add("y").add("z").build();
~~~
7) С помощью Stream.iterate() (бесконечный):
~~~
Stream<Integer> fromIterate = Stream.iterate(1, n -> n + 1);
~~~
8) С помощью Stream.generate() (бесконечный):
`Stream<String> fromGenerate = Stream.generate(() -> "0");`</String></Integer></String></String></String></String></String>

9) public static LongStream rangeClosed(long startInclusive, final long endInclusive) : range( start, excl).

Соединить 2 стрима:
Stream<Integer> stream3 = Stream.concat(stream1, stream2);

SINCE JAVA 11:
~~~
- public Stream<String> lines() :
Stream<String> stream = "Breaking news\n
a new version of Java\ris coming soon!".lines();
~~~</String></String>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

В чем разница между Collection и Stream?

A

Коллекции позволяют работать с элементами по-отдельности, тогда как стримы так делать не позволяют, но вместо этого предоставляют возможность выполнять функции над данными как над одним целым.

Также стоит отметить важность самой концепции сущностей: Collection - это прежде всего воплощение Структуры Данных. Например, Set не просто хранит в себе элементы, он реализует идею множества с уникальными элементами, тогда как Stream, это прежде всего абстракция необходимая для реализации конвейера вычислений, собственно, поэтому, результатом работы конвейера являются те или иные Структуры Данных или же результаты проверок/поиска и т.п.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Основные промежуточные методы Стримов.

A
  • <R> Stream<R> map(Function<? super T, ? extends R> mapper); : Returns a stream consisting of the results of applying the given function to the elements of this stream.
  • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
  • IntStream mapToInt(ToIntFunction<? super T> mapper) : Returns an IntStream consisting of the results of applying the given function to the elements of this stream. mapToDouble / mapToLong
  • Stream<Integer> boxed() : boxes int to Integer, used before collect()
- IntStream flatMapToInt(Function<? super T,
 ? extends IntStream> mapper) : 
superList.stream().flatMapToInt(x -> x.stream()
                                      .mapToInt(u->u)).min()...
  • Stream<T> filter(Predicate<? super T> predicate); : Returns a stream consisting of the elements of this stream that match the given predicate.

- Stream<T> limit(long maxSize) : Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.

  • Stream<T> skip(long n) : Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream
  • Stream<T> sorted(Comparator<? super T> comparator) : Returns a stream consisting of the elements of this stream, sorted according to the provided Comparator, or naturally if no Comparator provided.
  • Stream<T> distinct(); : Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
  • Stream<T> peek(Consumer<? super T> action) : Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element (like forEach but intermediate)

SINCE JAVA 9:- default Stream<T> takeWhile(Predicate<? super T> predicate)- default Stream<T> takeWhile(Predicate<? super T> predicate)
: suits for sorted streams, otherwise unpredictable.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Основные терминальные методы Стримов.

A
  • long count() : Returns the count of elements in this stream
  • Optional<T> findFirst() / findAny() : Returns an Optional describing the first (or any) element of this stream, or an empty Optional if the stream is empty.
  • boolean anyMatch(Predicate<? super T> predicate) / allMAtch/noneMatch
  • void forEach(Consumer<? super T> action) : Performs an action for each element of this stream. This is a terminal operation.
  • Optional<T> max / min (Comparator<? super T> comparator)
  • <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner) :
    without identity returns Optional,
    uses combiner when types of accumulator function mismatch:
    ~~~
    int result = users.stream().reduce(
    0, (partialAgeResult, user)-> partialAgeResult + user.getAge(),
    Integer::sum);
    ~~~
  • <R, A> R collect(Collector<? super T, A, R> collector) : Performs a mutable reduction operation on the elements of this stream using a Collector
  • <A> A[] toArray(IntFunction<A[]> generator) :
    ~~~
    Person[] men = people.stream()
    .filter(p -> p.getGender() == MALE)
    .toArray(Person[]::new);
    ~~~

Primitive Streams:
- int sum() : terminal, returns sum of els it this stream
- OptionalDouble average().orElse(0) :
- OptionalInt min().getAsInt : OptionalInt max().getAsInt

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Для чего нужен метод collect() в стримах?

A

collect() является конечной операцией, которая используется для представление результата в виде коллекции или какой-либо другой структуры данных:
- <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
or:

	`<R, A> R collect(Collector<? super T, A, R> collector) ` :
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

что такое Collector?

A

Коллектор задает способ комбинирования элементов стрима в единое целое.
Collector<Тип_источника, Тип_аккумулятора, Тип_результата>

В классе Collectors реализовано несколько распространённых коллекторов:

- toList(), toCollection(), toSet() :
~~~
CopyOnWriteArrayList<Integer> numbers =Stream.of(7, 4, 9, 11, 4)
.collect(Collectors.toCollection(CopyOnWriteArrayList::new));
~~~</Integer>

- toMap (Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator mergeFunction, Supplier mapFactory) :

public Map<String, String> listToMap(List<Book> books) {
return books.stream().collect(Collectors.toMap(
Book::getYear, Function.identity(),
(existing, replacer) ->existing, TreeMap::new));}

- partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream) : делит коллекцию на две части по соответствию условию, возвращает Map<Boolean, T> :
~~~
Map<Boolean, Long> map = Stream.of(1,2,3,4,5,).collect(
Collectors.partitioningBy(x->x > 3, Collectors.counting()));
~~~

- groupingBy(Predicate predicate, Supplier mapFactory, Collector downstream) - разделяет коллекцию на несколько частей и возвращает Map<N, T>>:

EnumMap<PostType, List<Post>> postsPerType = posts.stream()
  .collect(groupingBy(Post::getType, 
  () -> new EnumMap<>(PostType.class), toList()));

**- summingInt(ToIntFunction<? super T> mapper),
summingDouble(…), summingLong(…) **

- averagingInt(ToIntFunction<? super T> mapper),
averagingDouble(), averagingLong() :

~~~
double ans = Stream.of(“3”, “4”, “5”).
.collect(Collectors.averagingInt( num -> Integer.parseInt(num)));
~~~

**- minBy / maxBy (Comparator<? super T> comparator) : **
~~~
Optional<Log> minDelayLog = logs.stream()
.collect(Collectors.minBy(Comparator.comparing(Log::getDelay)));
~~~
**- mapping / flatMapping (Function mapper, Collector downstream) - дополнительные преобразования значений для сложных Collector-ов.**</Log>

- STRING COLLECTORS:

- joining() / joining(CharSequence delimiter)
/ joining(CharSeq delim, CharSeq pref, CharSeq suff) :

~~~
Stream.of(“Java”, “Kotlin”)
.collect(Collectors.joining(“, “, “<”, “>”)); // <Java, Kotlin>
NB: there is String.join(“ “, “Functions”, “in”, “Java”);
~~~

SINCE JAVA 9:

**- filtering(Predicatepredicate, Collector downstream) : **
~~~
Map<String, Long> popularTweetCountByLang = tweets.stream()
.collect(groupingBy(Tweet::getLang, filtering(
tweet -> tweet.getLikeCount() > 100, counting())));
~~~

- flatMapping(Function mapper, Collector downstream) :
~~~
Map<String, Long> commentCountPerTweetLang = tweets.stream()
.collect(groupingBy(Tweet::getLang, flatMapping(
tweet -> tweet.getComments().stream(), counting())));
~~~

Так же существует возможность создания собственного коллектора через Collector.of():
~~~
Collector<String, List<String>, List<String>> toList =
Collector.of(
ArrayList::new,
List::add,
(l1, l2) -> { l1.addAll(l2); return l1; }
);
~~~</String></String>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Как создать параллельный стрим?
Какие у него доп. методы?

A

создать:
- list.parallelStream() вместо list.stream()
- existing stream to parallel: numbers.stream().parallel()…

доп. методы:
- isParallel()
- sequential()

NB: если в стриме встречаются обе команды (parallel() & seqential()), то в итоге применяется последняя.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly