This is the 20th day of my participation in the August Text Challenge.More challenges in August

Lambda

A form of an anonymous function that has no name but a list of arguments, return types, and exceptions.

Custom functional interfaces

  1. There can only be one abstract method in an interface, but there can be more than onedefaultMethods.
  2. Comment on the interface@FunctionalInterfaceThe annotations and@OverrideSimilarly, it is a specification and can be omitted, but an error will be reported at compile time if the interface definition does not conform to the specification.

Eg:

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
Copy the code

Common functional interfaces

  1. Predicate

    Accept generics and return Boolean

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}
Copy the code
  1. Consumer

    Accept the generic type and return void

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
Copy the code
  1. Function

    Receiving generic T returns generic R

@FunctionalInterface
public interface Function<T.R> {
    R apply(T t);
}
Copy the code
  1. Supplier

Returns the generic T with no input parameter

@FunctionalInterface
public interface Supplier<T>{
    T get(a);
}
Copy the code
  1. Runnerable
@FunctionalInterface
public interface Runnable {
    public abstract void run(a);
}
Copy the code

Method references

A shortcut for calling a lambda for a particular method; A grammatical sugar.

If a Lambda simply stands for “call a method directly,” the call can be made directly by the method name.

The target reference is preceded by the :: delimiter, followed by the method

eg:

System.out::println

Constructor reference

For an existing constructor, you can use the name and keyword new to create a reference to it. ClassName::new does the same thing as pointing to a static reference.

eg:

class Apple{
    public Apple(a){}
    public Apple(Integer integer) {}
}
Supplier<Apple> s = Apple::new;
Function<Integer,Apple> f = Apple::new;
Copy the code

Stream

Streams exist for computation, collections exist for storage.

Eg: The following scenario: There is a string of numbers, and it is required to print the even numbers in the string without repeating them.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 4, 34, 65, 45, 765, 67, 325, 23);

  1. If we write it ourselves, first of all, find the even number, store it in the Set, and then print it through the Set.
HashSet<Integer> integerHashSet = new HashSet<>();
for(Integer temp:numbers){
    if(temp%2= =0){ integerHashSet.add(temp); }}for(Integer temp:integerHashSet){
    System.out.println(temp);
}
Copy the code
  1. After using stream calculation
numbers.stream()
        .filter(i->i%2= =0)
        .distinct()
        .forEach(System.out::println);
Copy the code

By contrast, the use of stream greatly simplifies development, and most importantly, we used the for loop twice before, but with the use of stream, instead of writing the loop statement, the developer handed the loop statement inside the stream. The advantage of this is that developers don’t have to worry about how the loop is iterated internally, which greatly simplifies development and readability.

Common flow operations

The method signature instructions
Stream<T> limit(long n); Returns the stream of the first n elements
Stream<T> skip(long n); Returns a stream that skips the first n elements
<R> Stream<R> map(Function<? super T, ? extends R> mapper) Take a function as an argument and map it to a new element
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); Flatten all streams into one stream
boolean allMatch(Predicate<? super T> predicate); Check that the predicate matches all elements
boolean anyMatch(Predicate<? super T> predicate); Check that the predicate matches at least one element
boolean noneMatch(Predicate<? super T> predicate); Whether no element of the content in the stream matches the given
Optional<T> findFirst(); Returns the first element in the stream
Optional<T> findAny(); Returns any element in the stream

FindFirst has more constraints than findAny and takes longer to execute.

Optional

Is a container class that represents the presence or absence of a value. His presence avoids null-pointer exceptions.

  • IsPresent () Optional includes returns true if it is worth it, false otherwise
  • IfPresent (Consumer Block) Optional executes the given code if it exists
  • T get() Optional returns the value if it exists, otherwise raises NoSuchElement
  • T orElse(T Other) Returns the value if the value exists, otherwise the default value is returned.

reduction

Reduce a function that provides iteration

Reduce accepts two parameters:

  • An initial value
  • aBinaryOperator<T>To combine elements to produce a new value

In addition, an overloaded method is provided

Initial values are not accepted. But it will return an Optional object. (Return Optional in case the computed value does not exist)

Eg:

Computes the sum of the given List.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

  • Traditional for-each
int count = 0;
for(Integer t:numbers){
      count+=t;
}
Copy the code
  • Lambda
Integer count = numbers.stream()
                       .reduce(0, (a, b) -> a + b);
Copy the code
Numerical flow

In the example above, where the elements are “unboxed” and evaluated during each iteration, which is a waste of time, Java provides an elegant stream for manipulating primitive data types.

  1. Common methods for mapping to numeric streams: mapToInt, mapToDouble, and mapToLong.

  2. The response’s numeric stream is replaced with an object stream method: boxed.

Build flow
  1. The flow is created from the value, just as it was created before.

    Stream<String> stringStream = Stream.of("python"."groovy"."scala");
    Copy the code
  2. Create streams from arrays

    int numbers[] = {3.2.5.8.4.7.6.9};
    Arrays.stream(numbers);
    Copy the code
  3. A stream is generated from a file

    NIO, which handles file I/O operations in Java,

    try(Stream<String> lines = Files.lines(Paths.get("filepath"),Charset.defaultCharset())) {
      	...
    } catch (IOException e) {
        e.printStackTrace();
    }
    Copy the code
  4. Generate streams from functions: Create infinite streams

    Stream AP provides two static methods to generate streams from functions, stream.iterate&stream.generate

    The generated stream will be endlessly evaluated by the function passed in, and should be limited with the use of limits.

    1. iterate

      Iterate takes an initial value, and a Lambda applied once for each new value produced

      eg:

      Stream.iterate(0,n->n+2)
              .limit(10)
              .forEach(System.out::println);
      Copy the code
    2. generate

      Generate accepts a Lambda that generates a new value

      Eg:

      Stream.generate(Math::random)
              .limit(5)
              .forEach(System.out::println);
      Copy the code

    The collector

    The collector provides three main functions

  • Specify and summarize elements into a value
  • Grouping elements
  • Element partition

The wheel test

  1. Find the maximum value in the stream
public void test6(a) {
    Optional<Dish> mostCalorieDish = menu.stream().max(comparingInt(Dish::getCalories));
    System.out.println(mostCalorieDish.get().getName());
}
Copy the code
  1. Calculate the total calories in a dish
public void test7(a) {
    Integer sum = menu.stream()
            .collect(summingInt(Dish::getCalories));
    System.out.println(sum);
}
Copy the code
  1. Connection string

    The parameter is a delimiter and may not be passed

public void test8(a) {
    String joinWords = menu.stream()
            .map(Dish::getName)
            .collect(joining("... ""));
    System.out.println(joinWords);
}
Copy the code
  1. grouping

    Customize a grouping method:

    private CaloricLevel getCaloricLevel(Dish dish) {
        if (dish.getCalories() <= 400) {
            return CaloricLevel.DIET;
        } else if (dish.getCalories() <= 700) {
            return CaloricLevel.NORMAL;
        } else {
            returnCaloricLevel.FAT; }}Copy the code
    1. Group dishes by category
    public void test3(a) {
        Map<CaloricLevel, List<Dish>> collect = menu.stream().collect(
                groupingBy(this::getCaloricLevel)
        );
    }
    Copy the code
    1. Multistage grouping
    public void test4(a) {
        Map<Dish.Type, Map<CaloricLevel, List<Dish>>> collect = menu.stream()
                .collect(
                        groupingBy(
                                Dish::getType, groupingBy(
                                        this::getCaloricLevel
                                )
                        )
                );
    }
    Copy the code
  2. You convert the results in the collector to another type and you group the dishes by category, and you take out the most caloric dishes in each group

    collectingAndThen

public void test9(a) {
    Map<Dish.Type, Dish> mostCaloricByType = menu.stream()
            .collect(
                    groupingBy(
                            Dish::getType,
                            collectingAndThen(
                                    maxBy(comparingInt(Dish::getCalories)),
                                    Optional::get)));
}
Copy the code

partition

Partitioning is a special case of grouping and returns only Boolean values,

  1. Separate dishes according to meat and vegetables
public void test10(a){
        Map<Boolean, List<Dish>> partitionMenu = menu.stream()
                .collect(
                        partitioningBy(Dish::isVegetarian)
                );
    }
Copy the code

The Collectors class commonly uses the static factory method

The factory method The return type instructions
toList List<T> Collect all the items into a List
toSet Set<T> Collect all items into a Set
toCollection Collection<T> Collect all items into a collection created by a given provider
counting Long Count the number of elements in the stream
summingInt Integer The sum of an integer property in the stream
averageingInt Double Returns the average value of the Integer items in the stream
summarizingInt IntSummaryStatistics Collect statistics on item Integer attributes in the stream, such as maximum, minimum, and average
joining String Concatenate the string generated by calling the toString method for each item in the stream
maxBy Optional<T> A report selects the largest element Optional in the stream for the given comparator, or option.empty () if the stream is empty.
reducing The type generated by the specification The iteration
collectingAndThen The return value type of the conversion function Wrap another collector and apply conversion functions to its results
groupingBy Map<K,List<T>> grouping
partitioningBy Map<Boolean,List<T>> partition

The Collector interface

public interface Collector<T.A.R> {
    /** * Creates a new container result */
    Supplier<A> supplier(a);

    /** * adds the element to the result container */
    BiConsumer<A, T> accumulator(a);

    /** * merges the two streams into one */
    BinaryOperator<A> combiner(a);

    /** * Apply the final transformation */ to the result container
    Function<A, R> finisher(a);

    /** * defines the behavior of the collector, whether streams can be specified in parallel. And those optimized hints, enumerations of three items * UNORDERED----- Protocol results are not affected by the order of traversal and accumulation in the project * CONCURRENT---- can be called from multiple threads simultaneously, The collector can parallel the protocol stream * IDENTITY_FINISH----- accumulator A converts unchecked to the result R is safe */
    Set<Characteristics> characteristics(a);
}
Copy the code

Parallel computing

Parallel computing framework in jdk1.7ForkJoin

This framework uses the classic algorithm —- divide-and-conquer algorithm, the task is divided into several sub-tasks, and then by the multi-thread parallel execution of sub-tasks, the default number of threads open by the NUMBER of CPU cores available to determine.

Demo: parallel computation adds up from 1 to N

public class ForkJoinSumCalculator extends java.util.concurrent.RecursiveTask<Long> {

    private final long[] numbers;
    /** * The start and end positions of the array processed by the subtask */
    private final int start;
    private final int end;

    /** * Array size that does not divide tasks into subtasks */
    public static final long THRESHOLD = 10 _000;

    private ForkJoinSumCalculator(long[] numbers, int start, int end) {
        this.numbers = numbers;
        this.start = start;
        this.end = end;
    }

    public ForkJoinSumCalculator(long[] numbers){
        this(numbers,0,numbers.length);
    }
    @Override
    protected Long compute(a) {
        int length = end - start;
        if (length <= THRESHOLD) {
            // If the size is less than or equal to the threshold, compute the results in order
            return computeSequentially();
        }
        ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(numbers, start, start + length / 2);
        // Another ForkJoinPool thread is used to execute the newly created subtask asynchronously
        leftTask.fork();

        ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(numbers, start + length / 2, end);

        Long rightResult = rightTask.compute();
        Long leftResult = leftTask.join();

        return rightResult + leftResult;
    }

    private Long computeSequentially(a) {
        long sum = 0;
        for (int i = start; i < end; i++) {
            sum += numbers[i];
        }
        return sum;
    }

    public static void main(String[] args) {
        long[] numbers = LongStream.rangeClosed(1.1000000).toArray();
        ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(numbers);
        Long invoke = newForkJoinPool().invoke(calculator); System.out.println(invoke); }}Copy the code

Work stealing

If we need to do a big task, we can put this task division for a number of mutually dependent child tasks, in order to reduce the competition between threads, then put these subtasks are different in the queue, and create a separate thread for each queue to perform the tasks in the queue, thread and queue one-to-one correspondence, For example, thread A handles tasks in queue A. However, some threads finish tasks in their queue first, while others have tasks in their queue. Instead of waiting, a finished thread can help another thread, so it steals a task from another thread’s queue to execute. In order to reduce the contention between the stolen thread and the stolen thread, a double-endian queue is usually used. The stolen thread always takes the task from the head of the double-endian queue, while the stolen thread always takes the task from the tail of the double-endian queue.

Jdk1.8 Spliterator

public interface Spliterator<T> {
    boolean tryAdvance(Consumer<? super T> action);
    Spliterator<T> trySplit(a);
    long estimateSize(a);
    int characteristics(a);
}
Copy the code
  1. T is the type to iterate over the Spliterator element.

  2. The tryAdvance method behaves like a normal Iterator

  3. TrySplit divides some elements into a second Spliterator and lets the two process them in parallel

  4. EstimateSize estimates how many elements are left to iterate over

  5. Characteristics returns an int that represents the encoding of Spliterator’s own feature set

The appendix

Recommended reading: github.com/winterbe/ja…