Spring Webflux

预备知识:

函数式编程,就是充分利用已经写好的函数,重点在于如何用这些函数实现功能

传统的命令式编程,就是要思考如何用一行行的代码实现功能

可以这样理解,传统的命令式编程就是在用代码实现函数功能,函数式编程是直接调用函数实现功能。

例子:命令式编程:通过for循环进行累加求和,这样就是去实现了求和的逻辑

函数式编程首先要了解lambda表达式,可以让代码更加简短。

Lambda表达式

实例: 匿名内部类省去了创建类的过程,而lambda表达式可以使这一过程更加简洁 public static void main(String args[]) { new Thread(){ @Override public void run() { System.out.pringln("OK"); } }.start(); 或 new Thread(new Runnable(){ @Override public void run() { System.out.println("ok"); } }).start(); } 使用lambda表达式: public static void main(String args[]) { new Thread(()-> System.out.println("ok")).start(); }

lambda本质是一个函数接口,用于快捷的创建一个接口实例并实现接口方法

表达式为:
()-> 方法

等价于
public class A implements B(){
    @Override
    public void kk() {
        。。。;
    }
}

有几个注意事项:

①lambda仅适用于只有一个需要重写方法的接口,这种接口也可称为函数式接口,如果有多个方法需要重写,就不能明确lambda表达式所编写的方法是重写的哪一个方法,只有一个需要重写方法的概念用下面的例子解释

下例中,虽然接口A有两个方法,但是仅有一个write方法需要重写,read为default方法不需要重写,所以A接口仍然可以用lambda表达式实现。

public class test {
    public static void main(String[] args) {
        A a = ()-> System.out.println("write");
        a.read();
        a.write();
    }
}

//对于函数式接口,可以加上@FunctionalInterface 加以标注,以表示其为一个函数式接口
@FunctionalInterface
interface A {
    public void write();
    default void read(){
        System.out.println("read");
    }
}

②lambda表达式实际返回的是实现接口的实例,所以必须用函数接口接收lambda表达式返回值

上例中,如果使用
Object a = ()-> System.out.println("write");
则会报错,因为Object并不是一个函数接口
可以强转类型解决
Object a = (A)()-> System.out.println("write");

以实现Runnable接口为例:
public class test {
    public static void main(String[] args) {
        Object r = (Runnable) ()-> System.out.println("run");
        Thread t = new Thread((Runnable)r);//传入的r也需要转换为Runnable类型
        t.start();
    }
}

下面介绍实现方法有参数的情况 该如何编写lambda表达式:

public class test {
    public static void main(String[] args) {
        //如果参数只有一个可以不写括号
        A a = (i, str)-> System.out.println(i + str);
        a.write(10,"strstr");
        //如果实现的方法体中有多行代码就需要加上{}
        A a = (i, str)-> {
            System.out.println(i + str);
            System.out.println("aa");
        };
        //方法有返回值,如果代码仅有一行 可以省略return,直接写返回值
        B b1 = (i, str)-> i * 2;
        System.out.println(b.read(20, "read"));
        //方法有返回,且有多行
        B b = (i, str)-> {
            System.out.println(str);
            return 2;
        };
        b.read(2, "read");
    }
}

interface A {
    public void write(int i,String str);
}
interface B {
    public int read(int i, String str);
}

Jdk1.8的函数接口

jdk1.8提供了很多函数接口,不需要定义特定的接口,只需要创建出具备输入输出的函数就可以

public static void main(String[] args) {
        //创建了一个接口实例a,所实现的方法是输入一个Integer类型的参数
        //输出为一个String类型的参数
        Function<Integer, String> a = (i)-> "aaa" + i;
        //使用apply方法调用所实现的接口方法
        String apply = a.apply(4);
        System.out.println(apply);
    }

//
Function<T, R> 可以用于创建一个输入为T类型,输出为R类型的函数 Customer<T> 用于创建一个有输入没输出的函数,消费者函数接口 Supplier<T> 用于创建一个有输出没输入的函数,生产者函数接口 参照上表以此类推

方法引用

若Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用,即Lambda的另外一种表现形式。方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致。

① 对象引用::实例方法名 @Test public void testT1() { // 创建一个User类,属性为name和age User user = new User("LCY", 22); // Lambda表达式 Supplier<String> sup1 = () -> user.getName(); System.out.println(sup1.get()); // 方法引用方式 Supplier<Integer> sup2 = user::getAge; System.out.println(sup2.get()); } ②类名::静态方法名 @Test public void testT2() { Comparator<Integer> com1 = (x,y) -> Integer.compare(x, y); System.out.println(com1.compare(1, 2)); Comparator<Integer> com2 = Integer::compare; System.out.println(com2.compare(7, 6)); } ③类名::实例方法名 @Test public void testT3() { BiPredicate<String, String> bp1 = (x,y) -> x.equals(y); System.out.println(bp1.test("abcd", "dcba")); // 参数1是调用equals的,参数2是equals方法的参数 // 因此可以使用类名::方法名 BiPredicate<String, String> bp2 = String::equals; System.out.println(bp2.test("123", "123")); }

类型判断:

package lambda; @FunctionalInterface interface IMath { int add(int x, int y); } @FunctionalInterface interface IMath2 { int sub(int x, int y); } public class TypeDemo { public static void main(String[] args) { // 变量类型定义 IMath lambda = (x, y) -> x + y; // 数组里 IMath[] lambdas = { (x, y) -> x + y }; // 强转 Object lambda2 = (IMath) (x, y) -> x + y; // 通过返回类型 IMath createLambda = createLambda(); TypeDemo demo = new TypeDemo(); // 当有方法重写,存在二义性的时候,使用强转对应的接口解决 demo.test( (IMath2)(x, y) -> x + y); } public void test(IMath math) { } public void test(IMath2 math) { } public static IMath createLambda() { return (x, y) -> x + y; } }

Jdk8 新特性Stream流编程

概念:通过Stream流的方法实现更高级的特性

外部迭代 和 内部迭代

实现数组内数字的累加
外部迭代:
int[] nums = {1, 2, 3};
int sum = 0;
for (int num :nums) {
    sum += num;
}

内部迭代:
int sum = IntStream.of(nums).sum();
通过流实现的方法更快捷的实现一些需求

中间操作/终止操作,惰性求值

int sum2 = IntStream.of(nums).map(i-> i * 2).sum();

System.out.println(sum2);

map就是一个中间操作返回一个Stream操作, sum就是一个终止操作,返回一个结果


public static void main(String[] args) {
        int[] nums = {1, 4, 3};

        IntStream intStream = IntStream.of(nums).map(i -> i * 2);
        System.out.println(intStream.sum());
    }

返回流的是中间操作,  返回结果的是终止操作

使用Stream操作的步骤:

①创建流

public static void main(String[] args) {
		List<String> list = new ArrayList<>();

		// 从集合创建
		list.stream();
		list.parallelStream();//并行流

		// 从数组创建
		Arrays.stream(new int[] { 2, 3, 5 });

		// 创建数字流
		IntStream.of(1, 2, 3);
		IntStream.rangeClosed(1, 10);

		// 使用random创建一个无限流
		new Random().ints().limit(10);
		Random random = new Random();

		// 自己产生流
		Stream.generate(() -> random.nextInt()).limit(20);

	}

②中间操作:

③终止操作

分为短路和非短路操作

短路操作:需要将整个流执行完,返回一个最终结果

短路操作:在执行流的过程中找到符合条件的结果并返回

并行流

经验分享 程序员 微信小程序 职场和发展