之前写了一篇博客简单介绍了一下java 8发布新增的一些特性功能,java 8在2014年发布,距今也不少年了,但是lambda表达式使用并不熟练,现在一边学习,一边记录一下。

目录

一、Lambda表达式

二、方法引用

三、stream API使用


一、Lambda表达式

是java8新增的最重要的新功能之一。使用Lambda表达式是 Java8 中最重要的新功能之一。使用 Lambda 表达式可以替代只有一个抽象方法的接口(函数式接口)实现,告别匿名内部类,代码看起来更简洁易懂。Lambda表达式同时还提升了对集合、框架的迭代、遍历、过滤数据的操作。

Lambda表达式特点

1:函数式编程

2:参数类型自动推断

3:代码量少,简洁

学习Lambda表达式需要熟悉java泛型,平时有意识地使用lambda表达式,学习java中固有的一些函数式接口,多用stream API。

函数式接口(函数式接口都可以使用Lambda表达式):只有一个抽象方法的接口

注意:如果自定义的接口使用Object类中的方法作为抽象方法,则该接口不是函数式接口。例如在接口中定义一个抽象方法:public int hashCode();

在java8中可以用@FuctionalInterface注解来验证函数式接口。

常用的函数式接口:

Runnable接口:

@FunctionalInterface
public interface Runnable {/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see     java.lang.Thread#run()*/public abstract void run();
}

Runnable接口是函数式接口因此可以使用lambda表达式。

Callable接口:

@FunctionalInterface
public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;
}

Comparator接口:

还有jdk中其他常用的函数式接口:

在java.util.function包下的类几乎都是函数式接口:

其中里面常用的接口有

Supplier接口:可以表示为一个输出(获取一个结果),返回T类型

@FunctionalInterface
public interface Supplier<T> {/*** Gets a result.** @return a result*/T get();
}

Consumer:可以表示为一个输入(操作一个输入的参数)

@FunctionalInterface
public interface Consumer<T> {/*** Performs this operation on the given argument.** @param t the input argument*/void accept(T t);/*** Returns a composed {@code Consumer} that performs, in sequence, this* operation followed by the {@code after} operation. If performing either* operation throws an exception, it is relayed to the caller of the* composed operation.  If performing this operation throws an exception,* the {@code after} operation will not be performed.** @param after the operation to perform after this operation* @return a composed {@code Consumer} that performs in sequence this* operation followed by the {@code after} operation* @throws NullPointerException if {@code after} is null*/default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };}
}

BiConsumer:可以表示为两个输入(有两个输入参数T和U)

@FunctionalInterface
public interface BiConsumer<T, U> {/*** Performs this operation on the given arguments.** @param t the first input argument* @param u the second input argument*/void accept(T t, U u);/*** Returns a composed {@code BiConsumer} that performs, in sequence, this* operation followed by the {@code after} operation. If performing either* operation throws an exception, it is relayed to the caller of the* composed operation.  If performing this operation throws an exception,* the {@code after} operation will not be performed.** @param after the operation to perform after this operation* @return a composed {@code BiConsumer} that performs in sequence this* operation followed by the {@code after} operation* @throws NullPointerException if {@code after} is null*/default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {Objects.requireNonNull(after);return (l, r) -> {accept(l, r);after.accept(l, r);};}
}

Function接口:可以表示为通过一个输入参数,获取一个输出(即一个输入,一个输出),传入一个T类型,获取一个R类型数据

@FunctionalInterface
public interface Function<T, R> {/*** Applies this function to the given argument.** @param t the function argument* @return the function result*/R apply(T t);/*** Returns a composed function that first applies the {@code before}* function to its input, and then applies this function to the result.* If evaluation of either function throws an exception, it is relayed to* the caller of the composed function.** @param <V> the type of input to the {@code before} function, and to the*           composed function* @param before the function to apply before this function is applied* @return a composed function that first applies the {@code before}* function and then applies this function* @throws NullPointerException if before is null** @see #andThen(Function)*/default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}/*** Returns a composed function that first applies this function to* its input, and then applies the {@code after} function to the result.* If evaluation of either function throws an exception, it is relayed to* the caller of the composed function.** @param <V> the type of output of the {@code after} function, and of the*           composed function* @param after the function to apply after this function is applied* @return a composed function that first applies this function and then* applies the {@code after} function* @throws NullPointerException if after is null** @see #compose(Function)*/default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));}/*** Returns a function that always returns its input argument.** @param <T> the type of the input and output objects to the function* @return a function that always returns its input argument*/static <T> Function<T, T> identity() {return t -> t;}
}

UnaryOperator接口:该接口继承了Funcition接口,可以表示为输入一个参数,获取一个输出数据(不同的是,输入和输出的类型相同了,都是T类型)

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {/*** Returns a unary operator that always returns its input argument.** @param <T> the type of the input and output of the operator* @return a unary operator that always returns its input argument*/static <T> UnaryOperator<T> identity() {return t -> t;}
}

BiFunction接口:表示两个输入(输入类型不同),一个输出(输入和输出类型都不同)

@FunctionalInterface
public interface BiFunction<T, U, R> {/*** Applies this function to the given arguments.** @param t the first function argument* @param u the second function argument* @return the function result*/R apply(T t, U u);/*** Returns a composed function that first applies this function to* its input, and then applies the {@code after} function to the result.* If evaluation of either function throws an exception, it is relayed to* the caller of the composed function.** @param <V> the type of output of the {@code after} function, and of the*           composed function* @param after the function to apply after this function is applied* @return a composed function that first applies this function and then* applies the {@code after} function* @throws NullPointerException if after is null*/default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t, U u) -> after.apply(apply(t, u));}
}

BinaryOperator接口:传入两个参数类型(输入),获取返回一个结果(输出),输入和输出类型相同

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {/*** Returns a {@link BinaryOperator} which returns the lesser of two elements* according to the specified {@code Comparator}.** @param <T> the type of the input arguments of the comparator* @param comparator a {@code Comparator} for comparing the two values* @return a {@code BinaryOperator} which returns the lesser of its operands,*         according to the supplied {@code Comparator}* @throws NullPointerException if the argument is null*/public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {Objects.requireNonNull(comparator);return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;}/*** Returns a {@link BinaryOperator} which returns the greater of two elements* according to the specified {@code Comparator}.** @param <T> the type of the input arguments of the comparator* @param comparator a {@code Comparator} for comparing the two values* @return a {@code BinaryOperator} which returns the greater of its operands,*         according to the supplied {@code Comparator}* @throws NullPointerException if the argument is null*/public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {Objects.requireNonNull(comparator);return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;}
}

其他的在这个包下还有一些接口名称带有类型的,可以顾名思义它的作用,如DoubleConsumer接口,则表示输入的参数类型为double类型,其他的类似,可以参考源码理解

@FunctionalInterface
public interface DoubleConsumer {/*** Performs this operation on the given argument.** @param value the input argument*/void accept(double value);/*** Returns a composed {@code DoubleConsumer} that performs, in sequence, this* operation followed by the {@code after} operation. If performing either* operation throws an exception, it is relayed to the caller of the* composed operation.  If performing this operation throws an exception,* the {@code after} operation will not be performed.** @param after the operation to perform after this operation* @return a composed {@code DoubleConsumer} that performs in sequence this* operation followed by the {@code after} operation* @throws NullPointerException if {@code after} is null*/default DoubleConsumer andThen(DoubleConsumer after) {Objects.requireNonNull(after);return (double t) -> { accept(t); after.accept(t); };}
}

labmda表达式语法,只有函数式接口可以使用lambda表达式(正因为函数式接口中只有一个抽象方法,所以lambda表达式不用写方法名,可以推断出来),lambda表达式是对象,是一个函数式接口的实例。

lambda表达式语法:LambdaParameter -> LambdaBody

例如 Runnable r=() -> System.out.println();

args -> expr

对应

(object... args)-> {函数式接口抽象方法的实现逻辑}

左边括号里边的参数个数,根据函数式接口里面抽象方法的参数个数决定。

当只有一个参数的时候,()可以省略,当方法体逻辑很简单的时候,{}和return 也可以省略

Lambda表达式示例:

() -> {}                             // 无参,无返回值

() -> { System.out.println(1); }   // 无参,无返回值

() -> System.out.println(1) // 无参,无返回值(上面的简写)

() -> { return 100; }      // 无参,有返回值

() -> 100                        // 无参,有返回值(上面的简写)

() -> null                       // 无参,有返回值(返回null)

(int x) -> { return x+1; }  // 单个参数(可以写出参数类型,不写类型,会自动推断,因此可以写成下边的形式)有返回值

(int x) -> x+1                // 单个参数,有返回值(上面的简写,省略了return)

(x) -> x+1                  // 单个参数,有返回值(不指定参数类型,因为可以根据接口中的抽象方法参数类型推断出来,多个参数必须用括号)

x -> x+1                     // 单个参数,有返回值(不指定参数类型)

注意事项:

多个参数类型时,要加上(),并且参数类型不能只省略一部分,

如:(x,int y)-> x+y

参数类型不能使用final修饰符,

如:(x, final y)-> x+y

不能将lambda表达式赋给一个非函数式接口

如:Object obj=()-> "hello"

可以将lambda表达式强转为一个有返回值的函数式接口

Object obj = (Supplier<?>)() -> "hello"

不需要也不允许使用throws语句来声明它可能会抛出的异常

实例演示:

package com.xiaomifeng1010.rbacboot.common.util;
import org.apache.commons.lang3.StringUtils;import java.io.Closeable;
import  java.util.Observer;import java.util.concurrent.Callable;
import java.util.function.*;/*** @author xiaomifeng1010* @version 1.0* @date: 2020/3/19 18:52*/public class LambdaExpression {public static void main(String[] args) throws Exception {//    无参无返回值接口Runnable,如果不使用lambda表达式,则是下边这样的Runnable runnable2=new Runnable() {@Overridepublic void run() {}};//    无参无返回值接口Runnable,使用lambda表达式,效果等同上边的Runnable runnable=() -> {};
//    如果方法体中只有一行逻辑实现的语句,大括号可以省略Runnable r=() -> System.out.println("无参无返回值的接口Runnable");Closeable closeable = () -> System.out.println("closeable也是无参无返回值");closeable.close();//  无参有返回值接口Callable,如果不使用lambda表达式Callable<String> callable=new Callable<String> () {@Overridepublic String call() {return "call方法";}};
//无参有返回值接口Callable,使用lambda表达式,效果等同上边的Callable<String> callable2 = () -> {return "call方法";};
//    因为方法体中只有一句返回语句,可以省略大括号和returnCallable callable3 = () -> "call方法";System.out.println(callable.call());System.out.println(callable2.call());System.out.println(callable3.call());//        有参无返回值自定义接口UserMapper,不使用lambda表达式时UserMapper userMapper=new UserMapper() {@Overridepublic void insert(User user) {System.out.println("插入一条数据");}};//    有参无返回值,使用lambda表达式时UserMapper userMapper2=(User user) -> System.out.println("插入一条数据");
//只有一个参数时,参数括号也可以省略,类型也可以省略(会自动推断)UserMapper userMapper3= user -> System.out.println("插入一条数据");//        有参有返回值的自定义接口OrderMapper,不使用lambda表达式OrderMapper orderMapper=new OrderMapper() {@Overridepublic int insert(Order order) {return 0;}};//    有参有返回值的自定义接口OrderMapper,使用lambda表达式(只有一个参数可省略括号和类型,方法体简单,只有一行可省略
// 大括号和returnOrderMapper orderMapper2=order -> 0;System.out.println("orderMapper插入了"+orderMapper.insert(new Order())+"行数据");System.out.println("orderMapper2插入了"+orderMapper2.insert(new Order())+"行数据");//        Function接口的使用示例,输入a是Integer类型,返回类型是String类型Function<Integer,String> function=a -> "function接口返回值";//     Function接口的使用示例,输入a是Integer类型,返回类型是String类型,由方法获取String.valueOf(b)返回String类型Function<Integer,String> function2 = b -> String.valueOf(b);System.out.println("function接口传入10,返回:"+function.apply(10));System.out.println("function2接口传入10,返回:"+function.apply(10));//        BiFunction输入两个不同类型参数(当然也可以相同类型参数),输出一个类型数据BiFunction<Integer,Double,String> biFunction=(a,b) -> String.valueOf(a)+String.valueOf(b);System.out.println("biFunction传入a,b值后:"+biFunction.apply(10,20.56));//        BinaryOperator输入的两个相同类型参数,输出相同类型的数据类型BinaryOperator<Integer> binaryOperator=(a,b) -> 10;System.out.println("binaryOperator输入a和b之后:"+binaryOperator.apply(5,6));//       Supplier接口获取一个输出Supplier<String> supplier = () -> "supplier";System.out.println("supplier不需要传入参数,就可以获取一个数据:"+supplier.get());//       Consumer输入一个类型参数,无返回值Consumer<String> consumer = (String s) -> {System.out.println("consumer");};
//        简写为:Consumer<String> consumer2 = s-> System.out.println("consumer");//        注意函数式接口的方法中有返回值的,使用lambda表达式方法体中必须要有返回值,且返回值类型要相同,而函数式接口抽象方法
//        没有返回值的,使用lambda表达式的方法体可以使用有返回值的方法。例如Runnable接口的抽象方法run()没有返回值;
//        Integer.parseInt()会返回int类型Runnable runnable4 =() -> Integer.parseInt("10");
//        但是直接写10,是不行的
//        Runnable runnable1 = () -> 10;
//        说明:为什么可以直接用方法,而不能直接使用int值,因为虽然Integer.parseInt("10")会返回一个int值,但是run
//        方法是无返回值的,所以调用Integer.parseInt("10")可以只是用他的方法逻辑,不用返回值,但是直接写10,就是直接给了
//        一个返回值,是不可以的}}/*** 自定义一个接口*/
@FunctionalInterfaceinterface UserMapper{void insert(User user);}
@FunctionalInterface
interface OrderMapper{int insert(Order order);
}class User{}class Order {}

写lambda表达式:

1.看抽象方法参数;2,看返回类型

二、方法引用

方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法,方法引用提供了一种引用而不执行方法的方式,如果抽象方法的实现恰好可以使用调用另外一个方法来实现,就有可能可以使用方法引用(因为如果方法体还需要写其他逻辑,就不能直接使用方法引用)。

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)方法引用:使用操作符“::” 将方法名和对象或类的名字分隔开来。
如下四种主要使用情况:

类型

语法

对应的lambda表达式

静态方法引用

类名::staticMethod

(args) -> 类名.staticMethod(args)

实例方法引用

inst::instMethod

(args) -> inst.instMethod(args)

对象方法引用

类名::instMethod

(inst,args)  ->类名.instMethod(args)

构造方法引用

类名::new

(args) -> new 类名(args)

如果函数式接口的实现恰好可以通过调用一个静态方法来实现,那么就可以使用静态方法引用;

如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用;

抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用;

如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用。
实例演示:

package com.xiaomifeng1010.rbacboot.common.util;import java.util.function.*;/*** @author xiaomifeng1010* @version 1.0* @date: 2020/3/19 21:32*/public class MethodReference {public static void main(String[] args) {
//        静态方法引用实例BinaryOperator<Double> binaryOperator=(a,b) -> Math.pow(a,b);
//        Math.pow(a,b)方法需要两个输入参数,返回一个数据,且输入参数类型和返回值类型相同,完全符合BinaryOperator
//        接口特点BinaryOperator<Double> binaryOperator2=Math::pow;//        构造方法引用
//      Supplier接口的get()方法不需要输入参数,返回一个值(输出),可以用
// String类(注意这里的String类不是lang包下的类,而是com.sun.org.apache.xpath.internal.operations.String)的构造方法实现Supplier<String> supplier=() -> new String();Supplier<String> supplier2=String::new;
//        类型也可以使用数组类型Function<Integer,Integer[]> function6=integer -> new Integer[integer];Function<Integer,Integer[]> function7=Integer[]::new;//        实例方法引用MethodReference mr = new MethodReference();Function<String,String> function3=str -> mr.toUpper(str);//        或者直接简写为(下边这种写法不用写MethodReference mr = new MethodReference()Function<String,String> function5=new MethodReference()::toUpper;
//      例子2,较特殊Function<String,String> function=str -> str.toUpperCase();
//        方法引用写法,因为toUpperCase()方法不是静态方法,但是直接使用String引用toUpperCase()方法Function<String,String> function2=String::toUpperCase;//        对象方法引用实例
//        抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。
//        如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用
//        lambda表达式方法体有现成方法实现时,lambda表达式完全写法(方法体中用类名.实例方法)Consumer<Too> consumer=(Too too) -> new Too().too();Consumer<Too> consumer2=Too::too;
//        接口中有两个参数的情况,BiConsumer接口接收两个输入参数,无返回值BiConsumer<Too,String> biConsumer=(Too too2,String str) -> new Too().top(str);BiConsumer<Too,String> biConsumer2=Too::top;//      接口中三个参数类型BiFunction<Too,String,String> biFunction=(Too too2,String str) -> new Too().tos(str);BiFunction<Too,String,String> biFunction2=Too::tos;//        说明:如果接口中的抽象方法中没有输入参数,不能使用对象方法引用}public String toUpper(String str){return str.toUpperCase();}}class Too{public void too(){}public void top(String str){}public String tos(String str){return str;}
}

三、stream API使用

Stream是一组用来处理数组、集合的API

Stream特性

1:不是数据结构,没有内部存储

2:不支持索引访问

3:延迟计算

4:支持并行

5:很容易生成数组或集合(List,Set)

6:支持过滤,查找,转换,汇总,聚合等操作

Stream运行机制

Stream分为 源source,中间操作,终止操作

流的源可以是一个数组、一个集合、一个生成器方法,一个I/O通道等等。

一个流可以有零个和或者多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用。一个流只会有一个终止操作。

Stream只有遇到终止操作,它的源才开始执行遍历操作。

Stream常用API

中间操作:

过滤 filter

去重 distinct

排序 sorted

截取 limit、skip

转换 map/flatMap

其他 peek

终止操作:

循环 forEach

计算 min、max、count、 average

匹配 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny

汇聚 reduce

收集器 toArray collect

Stream的创建

1、通过数组

2、通过集合来

3、通过Stream.generate方法来创建

4、通过Stream.iterate方法来创建

5、其他API创建

实例演示:

package com.xiaomifeng1010.rbacboot.common.util;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;/*** @author xiaomifeng1010* @version 1.0* @date: 2020/3/20 0:03*/public class StreamAPI {/*** 通过数组创建Stream*/static void generate1(){String letter="a,b,c,d,e,f,g";String[] array=letter.split(",");Stream<String> stream=Stream.of(array);stream.forEach(x -> System.out.println("generate1方法运行后:"+x));}/*** 通过集合创建Steam*/static void generate2() {List<String> list= Arrays.asList("a","b","c","d");Stream<String> stream=list.stream();stream.forEach(x -> System.out.println("依次输出:"+x));}/*** 通过Steam的静态方法generate()方法*/static void generate3() {
//    generate()方法中参数类型是函数式接口Supplier,产生一个无止境的steam流Stream<Integer> stream= Stream.generate(()->1);
//      会死循环(会一直调用supplier接口的get方法)
//      stream.forEach(x -> System.out.println("generate3方法运行后:"+x));
//       因此为了避免死循环,可以在终止操作前使用中间操作limit截断流stream.limit(10).forEach(x -> System.out.println("generate3方法运行后只取10个元素:"+x));}/*** 通过Steam的静态方法iterate()方法*/static void generate4(){
//    iterate()方法,第一个参数是初始元素,第二个参数类型是函数式接口UnaryOperator(输入和输出类型相同)
//      UnaryOperator输入的x后,一直累加1,无限制累加1循环,生成无止境steam流,初始值为1,然后一直往后加1Stream<Integer> stream= Stream.iterate(1,x -> x+1);
//      会死循环(会一直调用iterate不停迭代)
//      stream.forEach(x -> System.out.println("generate4方法运行后:"+x));
//     因此为了避免死循环,可以在终止操作前使用中间操作limit截断流,取前十个数stream.limit(10).forEach(x -> System.out.println("generate4方法运行后取前十位数:"+x));}/*** 通过String类的chars()方法创建*/static void generate5(){String letters="abcd";IntStream stream=letters.chars();
//      流的中间操作步骤可以有多步,或O部,为0则没有中间操作,可以直接使用终止操作,如直接操作stream的终止操作forEach:
//        stream.forEach(x -> System.out.println(x));
//        可以使用方法引用,会逐个输出a,b,c,d的ASCII码值(int类型)stream.forEach(System.out::println);}public static void main(String[] args) {
//      第一种和第二种创建流的方式使用较多
//        generate1();
//        generate2();
//        generate3();
//        generate4();
//        generate5();//        演示stream中间操作,但是在终止操作前会延迟计算,并不会真正计算,需要终止操作才能进行计算
//        Arrays.asList(1,2,3,4,5).stream().filter(x -> x%2==0);
//        加上终止操作(过滤掉其他的数字,只保留偶数输出),filter()方法中参数是函数式接口Predicate<T>,
//        boolean test(T t);Arrays.asList(1,2,3,4,5).stream().filter(x -> x%2==0).forEach(System.out::println);
//      过滤出来满足偶数的2,4,6的和,有返回值,可以终止int sum= Arrays.asList(1,2,3,4,5,6).stream().filter(x -> x%2==0).mapToInt(x -> x).sum();System.out.println("和为:"+sum);//        终止操作求最大值6int max=Arrays.asList(1,2,3,4,5,6).stream().max((a,b) -> a-b).get();System.out.println("最大值:"+max);//        查找满足过滤条件(偶数)中任一个int anyone= Arrays.asList(1,2,3,4,5,6).stream().filter(x -> x%2==0).findAny().get();System.out.println("查找满足过滤条件的任一个数据:"+anyone);//        查找满足过滤条件(偶数)的第一个(按排序从大到小 comparator中方法体用第二个参数减第一个参数)int findFirst= Arrays.asList(1,2,3,4,5,6).stream().filter(x -> x%2==0).sorted((a,b) -> b-a).findFirst().get();System.out.println("查找满足过滤条件的第一个数据:"+findFirst);//        根据字符串长短排序(长度从小到大排序,并迭代输出)Arrays.asList("com","xiaomifeng1010","cn","admin").stream().sorted((a,b) -> a.length()-b.length()).forEach(System.out::println);//        从1-50里面的所有偶数查找出来,存放到一个list中List<Integer> list=Stream.iterate(1,x -> x+1).limit(50).filter(x -> x%2==0).collect(Collectors.toList());System.out.println(list);//        去重操作Arrays.asList(1,3,4,5,6,3,5,7).stream().distinct().forEach(System.out::println);//        去重操作,将stream流转换成set集合类型(达到去重目的)Set<Integer> set= Arrays.asList(1,3,4,5,6,3,5,7).stream().collect(Collectors.toSet());System.out.println("set集合元素:"+set);//        产生1-50数据,分页效果(从大到小排序后,跳过10个数据,放在list中)List<Integer> list2= Stream.iterate(1,x -> x+1 ).limit(50).sorted((a,b) -> b-a).skip(10).collect(Collectors.toList());System.out.println("从50跳过10个数据后:"+list2);//        转换操作String str="11,22,33,44,55";
//       int sum2=Stream.of(str.split(",")).mapToInt(x -> Integer.parseInt(x)).sum();
//        写成方法引用int sum2=Stream.of(str.split(",")).mapToInt(Integer::parseInt).sum();System.out.println("字符串转换为int后求和:"+sum2);//       字符串对象,转换为Product对象String productName="iphone,ipad,macbook,flashlight";
//        Stream.of(productName.split(",")).map(x -> new Product(x)).forEach(System.out:: println);
//        方法引用Stream.of(productName.split(",")).map(Product::new).forEach(System.out:: println);//        演示peek操作,peek 操作接收的是一个 Consumer<T> 函数。顾名思义 peek 操作会按照 Consumer<T>
//        函数提供的逻辑去消费流中的每一个元素,同时有可能改变元素内部的一些属性Stream.of(productName.split(",")).peek(x -> x="hello"+x).forEach(System.out::println);//        当前的线程是主线程main,在peek方法中会输出main线程(串行方式,一直由main方法执行,即单线程)
//        由于stream流支持并行,使用parallel(中间操作)开启并行(多个线程执行)
//        Optional<Integer> max2=Stream.iterate(1,x -> x+1).limit(200).peek(x -> System.out.println(Thread.currentThread().getName()))
//                .parallel().max(Integer::compare);
//        System.out.println(max);//       并行流转换成串行流 (使用sequential()方法)
//        Optional<Integer> max3=Stream.iterate(1,x -> x+1).limit(200).parallel().peek(x -> System.out.println(Thread.currentThread().getName()))
//                .sequential().max(Integer::compare);
//        System.out.println(max);
//
//            }
}class Product{private String name;public Product(String name){this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Product{" +"name='" + name + '\'' +'}';}
}

控制台输出结果:

单元测试:实战应用

package com.xiaomifeng1010.rbacboot.common.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** @author xiaomifeng1010* @version 1.0* @date: 2020/3/21 12:47*/public class Java8LambdaTest {/*** 将请求的地址url中参数和值取出来存放到map中* url:http:localhost:8080/index.do?itemId=1&userId=1000&type=2&token=134jojmgoijeo4&key=index*/@Testpublic void test1() {String queryString ="itemId=1&userId=1000&type=2&token=134jojmgoijeo4&key=index";
//        将字符串queryString按照&分割为数组,并创建stream流Map<String,String> params= Stream.of(queryString.split("&"))
//                转换为(返回包含输出结果类型元素的stream,进一步按照等号分割的数组,保存在stream中).map(str -> str.split("="))
//                collect方法收集,内部Collectors.toMap()转换为map类型
//                toMap()方法中的参数为两个Function接口(第一个参数Function接口是获取map的key,
//                第一个参数Function接口是获取map的value
//                Function接口中输入参数s是数组,输出是数组元素,key是数组第一个元素,value是数组第二个元素
//                因为是元素依次输入,所以其实每次的数组都是只有两个元素.collect(Collectors.toMap(s -> s[0],s -> s[1]));System.out.println(params);}@Testpublic void test2 () {
//        通过ComputerBooks()获取list,创建流,获取ComputerBook对象所有id,在存放到list中List<Integer> ids = ComputerBooks().stream().map( ComputerBook -> ComputerBook.getId()).collect(Collectors.toList());System.out.println(ids);
//        方法引用ComputerBook::getIdids = ComputerBooks().stream().map(ComputerBook::getId).collect(Collectors.toList());System.out.println(ids);
//        获取ComputerBook对象所有id,然后以逗号方式连接拼接成字符串String str = ComputerBooks().stream().map(ComputerBook -> ComputerBook.getId()+"").collect(Collectors.joining(","));System.out.println(str);
//        获取ComputerBook对象所有id,然后以逗号方式连接拼接成字符串,并且以括号包裹str = ComputerBooks().stream().map(ComputerBook -> ComputerBook.getId()+"").collect(Collectors.joining(",", "(", ")"));System.out.println(str);str = ComputerBooks().stream().map(ComputerBook -> "'"+ComputerBook.getId()+"'").collect(Collectors.joining(",", "(", ")"));System.out.println(str);}@Testpublic void test3 () {
//       通过ComputerBooks()获取list,创建流,获取ComputerBook对象所有类型,在存放到list中
//        list中的泛型类型取决于map()方法转换输出类型(如本例中getType()方法)List<String> list = ComputerBooks().stream().map(ComputerBook::getType).collect(Collectors.toList());System.out.println(list);
//      通过ComputerBooks()获取list,创建流,获取ComputerBook对象所有类型(不重复的),在存放到list中list = ComputerBooks().stream().map(ComputerBook::getType).distinct().collect(Collectors.toList());System.out.println(list);
//      上边的也可以通过存放在set达到去重Set<String> set = ComputerBooks().stream().map(ComputerBook::getType).collect(Collectors.toSet());System.out.println(set);}@Testpublic void test4 () {
//        以ComputerBook类型的价格排序,价格由低到高排序
//      ComputerBooks().stream().sorted((ComputerBook1, ComputerBook2) -> Double.compare(ComputerBook1.getPrice(), ComputerBook2.getPrice())).forEach(System.out::println);;//       Comparator<ComputerBook> compa = (ComputerBook1, ComputerBook2) -> Double.compare(ComputerBook1.getPrice(), ComputerBook2.getPrice());
//        以ComputerBook类型的价格排序,价格由高到低排序(之前的排序规则反转一下)
//      ComputerBooks().stream().sorted(compa.reversed()).forEach(System.out::println);//        价格相同情况下,再比较出版日期
//      Comparator<ComputerBook> compa = (ComputerBook1, ComputerBook2) -> Double.compare(ComputerBook1.getPrice(), ComputerBook2.getPrice());
//      ComputerBooks().stream().sorted(compa.thenComparing((ComputerBook1,ComputerBook2) -> ComputerBook1.getPublishDate().isAfter(ComputerBook2.getPublishDate()) ? -1 : 1)).forEach(System.out::println);//       ComputerBooks().stream().sorted(Comparator.comparing(ComputerBook::getPrice)).forEach(System.out::println);
//      ComputerBooks().stream().sorted(Comparator.comparing(ComputerBook::getPrice).reversed()).forEach(System.out::println);ComputerBooks().stream().sorted(Comparator.comparing(ComputerBook::getPrice).reversed().thenComparing(Comparator.comparing(ComputerBook::getPublishDate).reversed())).forEach(System.out::println);}@Testpublic void test5 () {
//        将ComputerBook的id作为key,ComputerBook作为value存放到map中
//      Map<Integer, ComputerBook> ComputerBooksMap = ComputerBooks().stream().collect(Collectors.toMap(ComputerBook -> ComputerBook.getId(), ComputerBook -> ComputerBook));
//      System.out.println(ComputerBooksMap);Map<Integer, ComputerBook> ComputerBooksMap = ComputerBooks().stream().collect(Collectors.toMap(ComputerBook::getId, ComputerBook -> ComputerBook));System.out.println(ComputerBooksMap);}@Testpublic void test6 () {
//        统计平均价格(ComputerBook::getPrice对象方法引用)Double avg = ComputerBooks().stream().collect(Collectors.averagingDouble(ComputerBook::getPrice));System.out.println(avg);}@Testpublic void test7 () {
//        最高价的图书Optional<ComputerBook> computerBook = ComputerBooks().stream().collect(Collectors.maxBy(Comparator.comparing(ComputerBook::getPrice)));System.out.println(computerBook);
//         最低价的图书computerBook = ComputerBooks().stream().collect(Collectors.minBy(Comparator.comparing(ComputerBook::getPrice)));System.out.println(computerBook);
//         出版日期最早的书computerBook = ComputerBooks().stream().collect(Collectors.minBy(Comparator.comparing(ComputerBook::getPublishDate)));System.out.println(computerBook);
//         出版日期最晚的书computerBook = ComputerBooks().stream().collect(Collectors.maxBy(Comparator.comparing(ComputerBook::getPublishDate)));System.out.println(computerBook);
//          价格最高且日期最晚出版的图书(例子中有两本150的图书)Comparator<ComputerBook> comp = Comparator.comparing(ComputerBook::getPrice);computerBook = ComputerBooks().stream().collect(Collectors.maxBy(comp.thenComparing(Comparator.comparing(ComputerBook::getPublishDate))));System.out.println(computerBook);}@Testpublic void test8 () {
//        分组统计(按照类型),map中key为类型type
//      Map<String, List<ComputerBook>> ComputerBooksMap = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType));
//      ComputerBooksMap.keySet().forEach(key -> {
//          System.out.println(key);
//          System.out.println(ComputerBooksMap.get(key));
//          System.out.println("---------------------");
//      });
//          按照类型分组统计,并计算每种类型的数量
//      Map<String, Long> ComputerBooksCount = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType, Collectors.counting()));
//      System.out.println(ComputerBooksCount);
//          按照类型分组统计,并计算每种类型图书的价格合计
//      Map<String, Double> ComputerBooksSum = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType, Collectors.summingDouble(ComputerBook::getPrice)));
//      System.out.println(ComputerBooksSum);
//          按照类型分组统计,并计算每种类型图书的平均价格
//      Map<String, Double> ComputerBooksSum = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType, Collectors.averagingDouble(ComputerBook::getPrice)));
//      System.out.println(ComputerBooksSum);
//          按照类型分组统计,并计算每种类型图书价格的最大值
//      Map<String, Optional<ComputerBook>> ComputerBooksMaxPrice = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType, Collectors.maxBy(Comparator.comparing(ComputerBook::getPrice))));
//      System.out.println(ComputerBooksMaxPrice);
//          按照类型分组统计,并计算每种类型图书价格的最小值
//      Map<String, Optional<ComputerBook>> ComputerBooksMinPrice = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType, Collectors.minBy(Comparator.comparing(ComputerBook::getPrice))));
//      System.out.println(ComputerBooksMinPrice);
//          每种类型出版时间最晚的Map<String, Optional<ComputerBook>> ComputerBooksMaxPubDate = ComputerBooks().stream().collect(Collectors.groupingBy(ComputerBook::getType, Collectors.maxBy(Comparator.comparing(ComputerBook::getPublishDate))));System.out.println(ComputerBooksMaxPubDate);}@Testpublic void test9 () {
//        取出价格80元及以上的图书,按照出版日期从大到小排序ComputerBooks().stream().filter(ComputerBook -> ComputerBook.getPrice() >= 80).sorted(Comparator.comparing(ComputerBook::getPublishDate).reversed()).forEach(System.out::println);;}private List<ComputerBook> ComputerBooks(){List<ComputerBook> books = new ArrayList<>();books.add(new ComputerBook(1, "tomcat", 70d, "服务器", LocalDate.parse("2014-05-17")));books.add(new ComputerBook(2, "jetty", 60d, "服务器", LocalDate.parse("2015-12-01")));books.add(new ComputerBook(3, "nginx", 65d, "服务器", LocalDate.parse("2016-10-17")));books.add(new ComputerBook(4, "java", 66d, "编程语言", LocalDate.parse("2011-04-09")));books.add(new ComputerBook(5, "ruby", 80d, "编程语言", LocalDate.parse("2013-05-09")));books.add(new ComputerBook(6, "php", 40d, "编程语言", LocalDate.parse("2014-08-06")));books.add(new ComputerBook(7, "html", 44d, "编程语言", LocalDate.parse("2011-01-06")));books.add(new ComputerBook(8, "oracle", 150d, "数据库", LocalDate.parse("2013-08-09")));books.add(new ComputerBook(9, "mysql", 66d, "数据库", LocalDate.parse("2015-04-06")));books.add(new ComputerBook(10, "ssh", 70d, "编程语言", LocalDate.parse("2016-12-04")));books.add(new ComputerBook(11, "设计模式", 81d, "其他", LocalDate.parse("2017-04-06")));books.add(new ComputerBook(12, "重构", 62d, "其他", LocalDate.parse("2012-04-09")));books.add(new ComputerBook(13, "敏捷开发", 72d, "其他", LocalDate.parse("2016-09-07")));books.add(new ComputerBook(14, "从技术到管理", 42d, "其他", LocalDate.parse("2016-02-19")));books.add(new ComputerBook(15, "算法导论", 66d, "其他", LocalDate.parse("2010-05-08")));books.add(new ComputerBook(16, "oracle 12c", 150d, "数据库", LocalDate.parse("2017-05-08")));return books;}}
@Data
@AllArgsConstructor
class ComputerBook {private int id;private String name;private double price;private String type;private LocalDate publishDate;
}

@Data和@AllArgsConstrucor注解需要引入lombok依赖,以及idea中安装lombok插件。

java8 Lambda表达式的应用(函数式接口、lambda表达式,方法引用及Stream API)相关推荐

  1. Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)

    目录 ■代码 ■代码运行结果 ■代码说明 ・44行:Stream的.foreach方法ー参数类型:函数式接口 ・82行:Interface中,default方法 ・92行   Stream的.max方 ...

  2. java:java8新特性(Lambda 表达式、方法引用、构造器引用、数组引用、Stream API)

    速度更快 对 HashMap .ConcurrentHashMap低层的数据结构(数组+链表+二叉树) 低层的内存结构(将永久区更新为元空间,元空间使用的是物理内存) 代码更少(增加了新的语法 Lam ...

  3. jdk8新特性(Lambda、Steam、函数式接口)

    JDK8新特性 JDK8新特性 Lambda表达式 函数式(Functional)接口 方法引用与构造器引用 方法引用 构造器引用 强大的 StreamAPI 创建Stream方式 Stream 的中 ...

  4. Java8 新特性:Lambda 表达式、方法和构造器引用、Stream API、新时间与日期API、注解

    Java8新特性:Lambda 表达式.方法和构造器引用.Stream API.新时间与日期API.注解 1.Java8新特性 1.1.主要的新特性: 1.2.编程风格 2.Lambda 表达式 2. ...

  5. 学习 Java 8 - 函数式接口 Lambda

    学习 Java 8 - 函数式接口 Java 8 引入了函数式接口的概念.函数式接口其实就是只包含一个抽象方法的普通 Java 接口.在没有引入函数式接口之前,我们通常使用内部类和匿名类来实现类似的功 ...

  6. JAVA8的新特性之函数式接口

    JAVA8的新特性之函数式接口 1.Lambda表达式使用的前提,就是接口必须是一个函数式接口 2.定义 在接口中,只有一个抽象方法 3.检查是否是函数式接口用的注解 @FunctionalInter ...

  7. java 常用 函数式接口_「java8系列」神奇的函数式接口

    前言 在上一篇Lambda的讲解中我们就提到过函数式接口,比如:Consumer consumer = (s) -> System.out.println(s);其中Consumer就是一个函数 ...

  8. java8的4大核心函数式接口

    //java8的4大核心函数式接口//1.Consumer<T>:消费性接口//需求:public void happy(double money, Consumer<Double& ...

  9. Java23-day14【函数式接口(Supplier\Consumer\Predicate\Function)、Stream流(生产方式\中间方法\终结方法)】

    视频+资料[链接:https://pan.baidu.com/s/1MdFNUADVSFf-lVw3SJRvtg   提取码:zjxs] Java基础--学习笔记(零起点打开java世界的大门)--博 ...

最新文章

  1. R语言泊松回归模型案例:基于AER包的affair数据分析
  2. 《C语言编程初学者指南》一1.5 使用程序语句
  3. [转载]Android: 如何实现ScrollView中含有ListView?
  4. 第一篇 webApp启航
  5. echarts格式化tooltip数据
  6. C++开发WPF,Step by Step
  7. java8 两个list取差集_java8 多个list对象用lambda求差集操作
  8. 配置交换机端口聚合(思科、华为、锐捷)
  9. matlab 预测值一样,matlab BP神经网络建造如下,预测时,预测值反归一化报错,求大神指教!!!!!...
  10. nginx创建n个工作子进程
  11. CDOJ 1131 男神的礼物 区间dp
  12. K8s系列之:在容器内获取Pod信息(Downward API)
  13. 网络传输粘包解包处理
  14. Python——代码界的大门之一
  15. 定时刷新 定时刷新 定时刷新 定时刷新
  16. 如何做好SQLite 使用质量检测,让事故消灭在摇篮里
  17. 【ADB】设置adb输入法
  18. 3D视觉|了解下工业上常见的3D相机
  19. 详解数据架构的七类视图(多图+案例)
  20. Android Studio开发之报错-Compilation is not supported for following modules

热门文章

  1. 将Unix时间戳字符串转换为可读日期
  2. 计算机间盘的使用方法,电脑怎样分盘操作,史上最全分盘操作教程示意图
  3. win11任务栏卡死重启也没用怎么办
  4. 原生js的ajax的get怎么传参,原生js---ajax---get方法传数据
  5. vivox6android版本5.1,vivo X6 Plus的手机系统是什么?能升级安卓5.0吗?
  6. 洛谷——P1867 【Mc生存】经验值
  7. CSS3过渡练习-进度条(CSS3)
  8. 实验4-1-6 求分数序列前N项和 (15 分)
  9. 用过的人都知道,AWT_Swing_多选框功能可是很好用啊
  10. Numpy的使用方法