Lambda expressions

A lambda expression is an anonymous function, that is, a function without a function name

For example, we usually create threads

 / / Runnable implementation class
public class RunnableImpl implements Runnable {
     @Override
     public void run(a) {
         logger.info("The Runnable implementation class creates and starts a new thread"); }}// Create and start a thread using the traditional Runnable object
 new Thread(new RunnableImpl()).start();
 ​
 // Create and start a thread using an anonymous inner class
 new Thread(new Runnable() {
     @Override
     public void run(a) {
         logger.info("Create and start a new thread using an anonymous inner class.");
     }
 }).start();
 ​
 // Simplify anonymous inner classes as lambda expressions
 new Thread(()-> logger.info("Lambda expression creates and starts a new thread")).start();
 ​
Copy the code

Advantages: Lambda expressions have cleaner code than the traditional way of creating a Thread by passing a Runnable object as an argument to the Thread class

Method references

Method references encapsulate a method as a variable. :: Double colons are symbols for method references

 // method reference that converts the string 100 to an Integer type
 Function<String, Integer> function = Integer::parseInt;
 Integer IntegerResult= function.apply("100");
Copy the code

The return value type of a method reference is a functional interface

The parameter number, type, and return value type of the referenced method must be the same as the declaration of the method in the functional interface. As long as this requirement is met, any type of functional interface can be returned

 //Function The apply method accepts variables of type T and returns results of type R
 @FunctionalInterface
 public interface Function<T.R> {
     R apply(T t); } Integer.paseint () takes a string parameter and returns a result of type Integer// Compare two int values, either of the following return value types can be used
 Comparator<Integer> compare = Integer::compare;
 int compare1 = compare.compare(1.2);
 ​
 IntBinaryOperator compare = Integer::compare;
 int compare1 = compare.applyAsInt(1.2);
Copy the code

There are many functional interfaces under the java.util.function package

Customize a functional interface

@functionalInterface public interface KiteFunction<T,R,S> {R run(T T, S S); }Copy the code

Customize a method that corresponds to KiteFunction’s run method team

// The dateFormat method is used to format a date in a specified format. Public class TimeConverse {public static String dateFormat(LocalDateTime,String Pattern){public static String dateFormat(LocalDateTime,String Pattern){ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern); String dateStr = localDateTime.format(dateTimeFormatter); return dateStr; }}Copy the code
 KiteFunction<LocalDateTime, String, String> dateFormat = TimeConverse::dateFormat;
 String dateStr = dateFormat.run(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
 System.out.println(dateStr);
Copy the code

If the dateFormat method of TimeConverse is called only once, we can also implement it directly in the Run method of the kiteFunction interface (similar to how the Runnable interface creates and starts a new thread) as an anonymous inner class

 String dateStr2 = new KiteFunction<LocalDateTime, String, String>() {
             @Override
             public String run(LocalDateTime localDateTime, String pattern) {
                 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
                 return localDateTime.format(dateTimeFormatter);
             }
 ​
 }.run(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
Copy the code

The anonymous inner class above can be replaced with a lambda expression

 String dateStr2 = ((KiteFunction<LocalDateTime, String, String>) (localDateTime, pattern) -> {
             DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
             return localDateTime.format(dateTimeFormatter);
         }).run(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
Copy the code

The Stream flow

Stream makes extensive use of method references and lambda expressions, as well as a number of easy-to-use packaged utility apis that allow you to quickly and efficiently process complex data

  1. FlatMap flattens multidimensional data
  2. Peek is similar to foreach, except that foreach returns no result, while peek returns a Stream. However, if peek is executed without collecting data, no method inside the peek function is executed
  3. Reduce function to accumulate data
 // Reduce method definition
 Optional<T> reduce(BinaryOperator<T> accumulator);
 // Add the elements in List
      Integer result = stream.reduce((x, y) -> x + y).get(); X is the first element in Stream, and y is the second element//reduce overload method definition
 T reduce(T identity, BinaryOperator<T> accumulator);
 // The actual user assigns an initial value to the summation
 stream.reduce(100, (x, y) -> x + y),identity will be the first argumentCopy the code

Common methods of Stream processes

 Trader raoul = new Trader("Raoul"."Cambridge");
 Trader mario = new Trader("Mario"."Milan");
 Trader alan = new Trader("Alan"."Cambridge");
 Trader brian = new Trader("Brian"."Cambridge");
 ​
 List<Transaction> transactions = Arrays.asList(
     new Transaction(brian, 2011.300),
     new Transaction(raoul, 2012.1000),
     new Transaction(raoul, 2011.400),
     new Transaction(mario, 2012.710),
     new Transaction(mario, 2012.700),
     new Transaction(alan, 2012.950));//1. Find all trades in 2011 and sort them in reverse order
 List<Transaction> collect = transactions.stream().filter(t -> t.getYear() == 2011).sorted(Comparator.comparing(Transaction::getValue).reversed()).collect(Collectors.toList());
 System.out.println(collect);
 //2. What different cities have the traders worked in
 transactions.stream().map(Transaction::getTrader).map(Trader::getCity).distinct().forEach(e->System.out.println(e));
 //3. Determine whether traders have stayed in Milan
 boolean isExit = transactions.stream().map(Transaction::getTrader).map(Trader::getCity).anyMatch(e -> "Milan".equals(e));
 System.out.println(isExit);
 //4. Print all trades of traders living in Cambridge
 long sum = transactions.stream().filter(transaction -> "Cambridge".equals(transaction.getTrader().getCity())).collect(Collectors.summarizingInt(Transaction::getValue)).getSum();
 System.out.println("Total transaction value in Cambridge."+sum);
 //5. Of all the trades, the largest is
 Transaction transaction = transactions.stream().max(Comparator.comparing(Transaction::getValue)).get();
 System.out.println(transaction);
Copy the code

conclusion

When we talk about functional programming, functions are method references and expressions are Lambda expressions

The Stream Stream can improve our programming efficiency, but it also requires proper use of the StreamAPI and well-written comments when it comes to complex business logic