JAVA基础 函数式编程

目录

一、Lambda表达式

1.1 Lambda表达式介绍

1.2 Lambda作用

1.3 Lambda表达式语法

1.3.1 Lambda表达式结构

1.3.2 Lambda表达式的重要特征

1.3 Lambda表达式使用

1.3.1 定义函数接口并使用Lambda表达式实现函数接口

 1.3.2 简化Lambda表达式

1.3.3 Lambda表达式引用方法

 1.3.4 创建线程

 1.3.5 Lambda 表达式中的闭包问题

二、常用函数接口

 2.1 Consumer接口的使用

 2.2 Predicate接口的使用

 2.3 Comparator接口的使用

 三、Stream流

3.1 Stream流简介

 3.2 Stream流的常见方法

3.2.1 数据过滤

 3.2.2 数量限制

 3.2.3 元素排序


一、Lambda表达式

1.1 Lambda表达式介绍

 Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。

在Java语言中,可以为变量赋予一个值:

能否把一个代码块赋给一变量吗?

在Java 8之前,这个是做不到的。但是Java 8问世之后,利用Lambda特性,就可以做到了。

甚至我们可以让语法变得更简洁。

在Java 8里面,所有的Lambda的类型都是一个接口,而Lambda表达式本身,也就是”那段代码“,需要是这个接口的实现。这是我认为理解Lambda的一个关键所在,简而言之就是,Lambda表达式本身就是一个接口的实现。直接这样说可能还是有点让人困扰,我们继续看看例子。我们给上面的aBlockOfCode加上一个类型:

这种只有一个接口函数需要被实现的接口类型,我们叫它”函数式接口“。只要”函数式接口“才能使用Lambda表达式。为了避免后来的人在这个接口中增加接口函数导致其有多个接口函数需要被实现,变成"非函数接口”,我们可以在这个上面加上一个声明@FunctionalInterface, 这样别人就无法在里面添加新的接口函数了。

1.2 Lambda作用

最直观的作用就是使得代码变得异常简洁。

接口要求

虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法。

jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使用。也就是说一个接口中有且仅有一个抽象方法,还有default实现的方法也能使用Lambda表达式。

@FunctionalInterface注解作用:

@FunctionalInterface标记在接口上,“函数式接口”是指仅仅只包含一个抽象方法的接口。

1.3 Lambda表达式语法

1.3.1 Lambda表达式结构

语法结构:

(parameters) -> expression

(parameters) ->{ statements;}
 

语法形式为 () -> {}:

() 用来描述参数列表,如果有多个参数,参数之间用逗号隔开,如果没有参数,留空即可;

-> 读作(goes to),为 lambda运算符 ,固定写法,代表指向动作;

{} 代码块,具体要做的事情,也就是方法体内容;

1.3.2 Lambda表达式的重要特征

可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

可选的参数圆括号”()“:一个参数无需定义圆括号,但多个参数需要定义圆括号。

可选的大括号”{ }“:如果主体包含了一个语句,就不需要使用大括号。

可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

// 1. 不需要参数,返回值为 5 
() -> 5 
 
// 2. 接收一个参数(数字类型),返回其2倍的值 
x -> 2 * x 
 
// 3. 接受2个参数(数字),并返回他们的差值 
(x, y) -> x – y 
 
// 4. 接收2个int型整数,返回他们的和 
(int x, int y) -> x + y 
 
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) 
(String s) -> System.out.print(s)

1.3 Lambda表达式使用

1.3.1 定义函数接口并使用Lambda表达式实现函数接口

函数接口指的是在该接口中只能含有一个抽象方法。可以有多个default修饰的方法或者是static方法。

package cn.it.bz.Lambda;


//无返回值无参数的函数接口
@FunctionalInterface
interface NoReturnNoParam{
    public void method();
}

//无返回值有一个参数的函数接口
@FunctionalInterface
interface NoReturnOneParam {
    public void method(int a);
}

//无返回值有两个参数的函数接口
@FunctionalInterface
interface NoReturnManyParam {
    public void method(int a, int b);
}

//有返回值的无参数函数接口
@FunctionalInterface
interface ReturnNoParam {
    public int method();
}

//有返回值有一个参数的函数接口
@FunctionalInterface
interface ReturnOneParam {
    public int method(int a);
}

//有返回值有两个参数的函数接口
@FunctionalInterface
interface ReturnManyParam {
    public int method(int a, int b);
}

public class Test {
    public static void main(String[] args) {
        //无返回值无参数的函数接口实现,类型就是接口名称,{}表示对抽象方法的具体实现
        NoReturnNoParam noReturnNoParam = () -> {
            System.out.println("noReturnNoParam");
        };
        //调用该方法
        noReturnNoParam.method();

        System.out.println("----------------------");

        //无返回值一个参数的接口实现
        NoReturnOneParam noReturnOneParam = (int a) -> {
            System.out.println("noReturnOneParam"+a);
        };
        //调用该方法
        noReturnOneParam.method(1);

        System.out.println("---------------------");

        //无返回值的两个参数的接口实现
        NoReturnManyParam noReturnManyParam = (int a, int b) -> {
            System.out.println("noReturnManyParam"+a+","+b);
        };
        //调用该方法
        noReturnManyParam.method(1, 2);

        System.out.println("--------------------");

        //有返回值无参数的函数接口实现
        ReturnNoParam returnNoParam = () -> {
            System.out.println("returnNoParam");
            return 123;
        };
        //调用该方法
        int a = returnNoParam.method();
        System.out.println("a="+a);

        System.out.println("---------------------");

        //有返回值有一个参数的函数接口实现
        ReturnOneParam returnOneParam = (int a1) -> {
            System.out.println("returnOneParam"+a1);
            return a1;
        };
        //调用该方法
        int b = returnOneParam.method(1);
        System.out.println("b="+b);

        System.out.println("--------------------");

        //有返回值有两个参数的函数接口实现
        ReturnManyParam returnManyParam = (int a1, int a2) -> a1 + a2;
        // 调用该方法
        int c = returnManyParam.method(1, 2);
        System.out.println("c="+c);


    }
}

 1.3.2 简化Lambda表达式

1、只有一个参数时小括号可以省略。

2、参数列表中的参数可以写,可以不写。要写都写,

3、当方法体之哟一行代码时,大括号可以省略。

4、方法体中只有一行return时,return可以省略。

package cn.it.bz.Lambda;


//无返回值无参数的函数接口
@FunctionalInterface
interface NoReturnNoParam{
    public void method();
}

//无返回值有一个参数的函数接口
@FunctionalInterface
interface NoReturnOneParam {
    public void method(int a);
}

//无返回值有两个参数的函数接口
@FunctionalInterface
interface NoReturnManyParam {
    public void method(int a, int b);
}

//有返回值的无参数函数接口
@FunctionalInterface
interface ReturnNoParam {
    public int method();
}

//有返回值有一个参数的函数接口
@FunctionalInterface
interface ReturnOneParam {
    public int method(int a);
}

//有返回值有两个参数的函数接口
@FunctionalInterface
interface ReturnManyParam {
    public int method(int a, int b);
}

public class Test {
    public static void main(String[] args) {
        //无返回值无参数的函数接口实现
        //方法体只有一行代码时,{}可以不写。
        NoReturnNoParam noReturnNoParam = () -> System.out.println("noReturnNoParam");;
        //调用该方法
        noReturnNoParam.method();

        System.out.println("----------------------");

        //无返回值一个参数的接口实现
        //当参数只有一个时,()可以不写;方法体只有一行代码时,{}可以不写。
        NoReturnOneParam noReturnOneParam = a-> System.out.println("noReturnOneParam"+a);;
        //调用该方法
        noReturnOneParam.method(1);

        System.out.println("---------------------");

        //无返回值的两个参数的接口实现
        //方法体只有一行代码时,{}可以不写。
        NoReturnManyParam noReturnManyParam = (int a, int b) -> System.out.println("noReturnManyParam"+a+","+b);;
        //调用该方法
        noReturnManyParam.method(1, 2);

        System.out.println("--------------------");

        //有返回值无参数的函数接口实现
        ReturnNoParam returnNoParam = () -> {
            System.out.println("returnNoParam");
            return 123;
        };
        //调用该方法
        int a = returnNoParam.method();
        System.out.println("a="+a);

        System.out.println("---------------------");

        //有返回值有一个参数的函数接口实现
        //当参数只有一个时,()可以不写;
        ReturnOneParam returnOneParam = (int a1) -> {
            System.out.println("returnOneParam"+a1);
            return a1;
        };
        //调用该方法
        int b = returnOneParam.method(1);
        System.out.println("b="+b);

        System.out.println("--------------------");

        //当方法体只有return一行代码时,return可以不写。
        ReturnManyParam returnManyParam = (int a1, int a2) -> a1 + a2;
        // 调用该方法
        int c = returnManyParam.method(1, 2);
        System.out.println("c="+c);
    }
}

1.3.3 Lambda表达式引用方法

有时候我们不是必须使用Lambda的函数体定义实现,我们可以利用 lambda表达式指向一个已经存在的方法作为抽象方法的实现。

要求

  • 参数的个数以及类型需要与函数接口中的抽象方法一致。

  • 返回值类型要与函数接口中的抽象方法的返回值类型一致。

语法

方法归属者::方法名 静态方法的归属者为类名,非静态方法归属者为该对象的引用。 

package cn.it.bz.Lambda;

@FunctionalInterface
interface ReturnOne {
    public int method(int a);
}

public class Test2 {

    //静态方法
    public static int doubleNumber(int a){ return a*2; }
    //非静态方法
    public int doubleNumber2(int a) {return a * 2;}

    public static void main(String[] args) {

        //将静态方法作为接口中抽象方法的实现方法(前提是参数个数和参数类型必须相同)
        //Test2::doubleNumber表示抽象方法的实现方法是Test类下的doubleNumber方法
        ReturnOne returnOne1 = Test2::doubleNumber;
        //调用
        int method = returnOne1.method(10);
        System.out.println(method);

        //将非静态方法作为接口中抽象方法的实现方法
        //先实例化非静态方法的归属者,通过对象引用实现
        Test2 test2 = new Test2();
        ReturnOne returnOne2 = test2::doubleNumber2;
        int method1 = returnOne1.method(20);
        System.out.println(method1);



    }
}

 1.3.4 创建线程

package cn.it.bz.Lambda;

//Runnable接口中只有一个抽象方法run,也就是说Runnable是个函数接口。
public class Test3 {
    public static void main(String[] args) {
        System.out.println("主线程"+ Thread.currentThread().getName()+"启动!");

        //Lambda表达式实现run 方法。
        Runnable runnable = () -> {
            for (int i = 0; i < 10; i++ ) {
                System.out.println(Thread.currentThread().getName() + ", "+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                }
            }
        };

        //线程包装
        Thread thread = new Thread(runnable, "Lambda线程");
        //线程启动
        thread.start();

        System.out.println("主线程"+ Thread.currentThread().getName()+"结束!");

    }
}
 //或者直接将run方法的实现放在Thread构造方法中。
        new Thread(() -> {
            for (int i = 0; i < 10; i++ ) {
                System.out.println(Thread.currentThread().getName() + ", "+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                }
            }
        }, "Lambda线程").start();

 1.3.5 Lambda 表达式中的闭包问题

什么是闭包

闭包的本质就是代码片断。所以闭包可以理解成一个代码片断的引用。在Java中匿名内部类也是闭包的一种实现方式。

在闭包中访问外部的变量时,外部变量必须是final类型,虚拟机会帮我们加上 final 修饰关键字。

二、常用函数接口

 2.1 Consumer接口的使用

Consumer 接口是JDK为我们提供的一个函数式接口,该接口也被称为消费型接口。

遍历集合

我们可以调用集合的 public void forEach(Consumer<? super E> action) 方法,通过 lambda 表达式的方式遍历集合中的元素。以下是 Consumer 接口的方法以及遍历集合的操作。

实现方式一:

package cn.it.bz.Lambda;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

class ConsumerImpl implements Consumer {

    //Object就是要消费的数据。
    @Override
    public void accept(Object o) {
        System.out.println(o+"O(∩_∩)O");
    }
}

public class TestConsumer {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
       /* forEach可以实现取出集合中的元素但是不知道怎么处理取出的元素。
        forEach方法需要的参数是Consumer接口实现类的对象,也就是说我需要给forEach
        一个能消费它遍历出来的元素的对象。*/
        list.forEach(new ConsumerImpl());

    }
}

 方式二:

如果仅仅是为了输出遍历的数据的话,这样写未免有些麻烦。我们平时使用的输出语句是System.out.println,打开API文档

 

我们可以发现,out实际上是System类下的静态成员变量,返回的是一个PrintStream类型的数据,该类下的println方法是个无返回值的含有一个Object类型参数的非静态方法。这和Consumer接口中的抽象方法accept的结构一毛一样,因此我们可以使用Lambda表达式将printlin方法作为accept的实现方法。

package cn.it.bz.Lambda;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

public class TestConsumer {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");

        //将PrintStream类下的println方法作为Consumer接口的抽象方法accept方法的实现方法。
        PrintStream out = System.out;
        list.forEach(out::println);
    }
}

 2.2 Predicate接口的使用

Predicate 是 JDK 为我们提供的一个函数式接口,可以简化程序的编写。

删除集合中的元素

我们通过public boolean removeIf(Predicate<? super E> filter)方法来删除集合中的某个元素,

package cn.it.bz.Lambda;


import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

class PredicateImpl implements Predicate {

    @Override
    public boolean test(Object o) {
        return "b".equals(o);
    }
}

public class TestPredicate {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //实例化PredicateImpl
        PredicateImpl predicateImpl = new PredicateImpl();
        list.removeIf(predicateImpl);
//        //或者使用Lambda表达式
//        list.removeIf((o)-> o.equals("b"));

        //查看集合中是否还存在b元素
        Consumer consumer = (a) -> System.out.println(a);
        list.forEach(consumer);
    }
}

 2.3 Comparator接口的使用

Comparator是 JDK 为我们提供的一个函数式接口,该接口为比较器接口。

元素排序

之前我们若要为集合内的元素排序,就必须调用 sort 方法,传入比较器重写 compare 方法的比较器对象,现在我们还可以使用 lambda 表达式来简化代码。

 排序方式一:

package cn.it.bz.Lambda;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;


class ComparatorImpl implements Comparator<String> {

    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
}

public class TestComparator {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("c");
        list.add("d");
        list.add("b");
        list.add("a");
        //元素排序
        ComparatorImpl comparatorImpl = new ComparatorImpl();
        list.sort(comparatorImpl);
        //输出
        list.forEach(System.out::println);
    }
}

 方式二使用Lambda表达式、

package cn.it.bz.Lambda;

import java.util.ArrayList;
import java.util.List;

public class TestComparator {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("c");
        list.add("d");
        list.add("b");
        list.add("a");
        //元素排序
        list.sort((o1,o2) ->o1.compareTo(o2));
        //输出
        list.forEach(System.out::println);
    }
}

 三、Stream流

3.1 Stream流简介

Stream是数据渠道,用于操作数据源所生成的元素序列,它可以实现对集合的复杂操作,例如过滤、排序和映射等。Stream不会改变源对象,而是返回一个新的结果集。

Stream流的生成方式

  • 生成流:通过数据源(集合、数组等)创建一个流。
  • 中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用。
  • 终结操作:一旦执行终止操作,就执行中间的链式操作,并产生结果。

collection接口中有一个Stream类型的方法,该接口下的实现类实现了该抽象方法,也就是说Collection接口下的List、set等单例集合都存在一个Stream方法返回一个对应的Streatm对象。

 3.2 Stream流的常见方法

3.2.1 数据过滤

package cn.it.bz.Lambda;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestStream {
    public static void main(String[] args) {
        //生成Stream流对象
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("O(∩_∩)O");
        list.add("张三");
        list.add("张无形");
        Stream<String> stream = list.stream();
        //操作流对象
        //数据过滤,实现多条件and关系,以张开头三结尾的元素
        List<String> collect = stream.filter(o -> o.startsWith("张")).filter(o -> o.endsWith("三")).collect(Collectors.toList());
        //遍历过滤后的结合
        collect.forEach(System.out::println);

        System.out.println("--------------------");


        Stream<String> stream1 = list.stream();
        //多条件的or关系
        //先创建or关系
        Predicate<String> predicate = (o) ->o.startsWith("张");
        Predicate<String> predicate2 = (o) -> o.startsWith("O");
        List<String> collect1 = stream1.filter(predicate.or(predicate2)).collect(Collectors.toList());
        //遍历过滤后的结合
        collect1.forEach(System.out::println);
    }
}

 3.2.2 数量限制

package cn.it.bz.Lambda;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestStream2 {
    public static void main(String[] args) {
        //生成Stream流对象
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("O(∩_∩)O");
        list.add("张三");
        list.add("张无形");
        Stream<String> stream = list.stream();
        //获取前两个元素
        List<String> collect = stream.limit(2).collect(Collectors.toList());
        //遍历
        collect.forEach(System.out:: println);

    }
}

 3.2.3 元素排序

package cn.it.bz.Lambda;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestStream3 {
    public static void main(String[] args) {
        //生成Stream流对象
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("O(∩_∩)O");
        list.add("张三");
        list.add("张无形");
        //按照升序排序
        List<String> collect = list.stream().sorted().collect(Collectors.toList());
        //遍历
        collect.forEach(System.out::println);
        System.out.println("--------------------");
        //降序
        list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

    }
}

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 以下是几本 Java 函数式编程方面的书籍: 1. 《Java 8 实战》(Java 8 in Action):作者是 Raoul-Gabriel Urma、Mario Fusco 和 Alan Mycroft。这本书讲解了 Java 8 中的新特性,其中包括函数式接口、Lambda 表达式、流式 API 等。适合已有一定 Java 基础的读者。 2. 《Java 函数式编程》(Functional Programming in Java):作者是 Venkat Subramaniam。这本书从 Java 函数式编程基础开始,逐步讲解了函数式编程的概念和技术。该书强调了函数式编程的优点,并提供了许多实例和案例。 3. 《Java 8 函数式编程》(Java 8 Functional Programming):作者是 Richard Warburton。这本书从 Java 8 开始讲解函数式编程。其中包括函数式编程的核心概念、Lambda 表达式、流式 API 等。该书还提供了大量实例和案例。 4. 《函数式思维:函数式编程入门指南》(Functional Thinking: Paradigm Over Syntax):作者是 Neal Ford。这本书从函数式编程的角度讲解了软件开发中的许多常见问题。它强调了函数式编程的思维方式,并讨论了如何在现有的 Java 代码中使用函数式编程的概念和技术。 这些书籍都是非常优秀的 Java 函数式编程方面的参考书籍,建议根据自己的实际需要进行选择。 ### 回答2: Java函数式编程是指在Java编程语言中使用函数式编程的技术和方法。这种编程范式的特点是把函数作为一等公民,可以作为参数传递、作为返回值,可以被存储在变量中。Java函数式编程的核心思想是通过使用lambda表达式和函数接口(Functional Interface)实现函数的定义、调用和组合,以达到简化代码、提高可读性和减少冗余的目的。 《Java编程思想》(Thinking in Java)第5版是一本经典的Java编程书籍,可以作为入门级的Java函数式编程指南。该书详细介绍了Java编程语言的各个方面,包括面向对象编程、多线程、异常处理等,同时也提供了一些关于函数式编程的内容。 《Java函数式编程》(Java 8 in Action)是一本深入介绍Java函数式编程的书籍。该书讲解了Java 8引入的函数式编程特性,如lambda表达式、函数接口和流(Stream)等。通过具体的示例和案例,读者可以了解到如何使用这些特性来编写简洁、高效的函数式程序。 《函数式编程思维》(Functional Thinking)是另一本值得推荐的Java函数式编程书籍。该书主要介绍了函数式编程的思维方式和经典的函数式编程概念,如函数组合、高阶函数和惰性求值等。通过深入理解这些概念,读者可以更好地应用函数式编程技术解决实际问题。 总之,选择一本合适的Java函数式编程书籍,对于提高自己的编程能力和理解函数式编程思想都是非常有帮助的。通过学习函数式编程,我们可以更好地利用Java语言的特性,编写出高质量的、易于维护的代码。 ### 回答3: Java函数式编程是利用函数作为一等公民的编程范式,它能够提供更加灵活、简洁和可复用的代码。以下是一些关于Java函数式编程的书籍推荐: 1. 《Java 8实战》 - 这本书由著名的Java专家实践者撰写,详细介绍了Java 8中引入的函数式编程特性,如Lambda表达式、流式编程和方法引用等。它提供了大量的示例和案例,帮助读者快速理解和应用这些特性。 2. 《Java函数式编程》 - 这本书详细讲解了Java中的函数式编程概念和方法,并介绍了函数式编程的核心概念,如高阶函数、纯函数和不可变性等。它还介绍了函数式编程的一些常用库和框架,如Guava和RxJava等。 3. 《函数式编程思维》 - 这本书并不是专门针对Java函数式编程,而是介绍了函数式编程的一般思维方式和方法。它讲解了函数式编程的核心思想和原则,并提供了一些通用的实践技巧和设计模式。这本书可以帮助读者更好地理解和应用函数式编程的概念。 4. 《Java 8函数式编程》 - 这本书是专门为Java开发者准备的函数式编程指南。它介绍了Java 8中的函数式编程特性,并提供了一些实践案例和示例代码,帮助读者快速上手函数式编程。 5. 《Lambda编程指南》 - 这本书重点介绍了Java 8中引入的Lambda表达式和函数式接口,并详细讲解了它们的语法和用法。它还介绍了一些常用的函数式编程库和工具,如Stream API和函数式接口库。 以上是一些关于Java函数式编程的书籍推荐,它们可以帮助读者更好地理解和应用函数式编程的概念和技巧。无论是初学者还是有经验的Java开发者,都可以从这些书籍中获得实用的知识和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张小猿ε٩(๑> ₃ <)۶ з

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值