JavaSE---常用的API

news2024/9/24 7:21:12

1. 什么是API?

  • API (Application Programming interface) 应用程序编程接口。
  • 通俗来讲,就是Java已经帮我们写好了一些方法,我们直接拿过来用即可。

iodraw:https://www.iodraw.com/

API在线中文文档:https://www.matools.com/api/java8

image-20220630073311584

当然也可以IntelliJ 在IDEA中查看Java源码。


2. Object、Objects类

2.1 Object类

  • Object类位于java.lang包,在Java中所有的类都是直接或者间接继承该类。

  • Object类的方法是一切子类都可以使用的。

    Object类常用的方法:

方法名说明
public String toString()默认是返回当前对象在堆内存中的地址信息:类的全限定名@内存地址
public boolean equals(Object obj)默认是比较两个对象的地址是否相同(==),相同返回true,不同返回false
public final Class getClass()返回Class类型的对象
protected Object clone()创建并返回此对象的副本
public int hashCode()返回该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算。

不同对象的 hashCode的值一般是不相同。但是,同一个对象的hashCode值肯定相同。

image-20220630080436586


2.2 Objects类

  • Objects类与Object还是继承关系,它位于java.util包,Objects类是JDK1.7之后开始有的。
  • 相比之下Objects中的equals()方法更加安全(多了个非空判断)。
public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

Objects类的常用方法:

方法名说明
public boolean equals(Object a,Object b)比较两个对象的地址是否相同,底层会先进行非空判断,从而可以避免空指针异常。再进行equals比较
public static boolean isNull(Object obj)判断变量是否为null

3. Math类

  • Math类提供了一些数字运算的方法(如:指数,对数,平方根、三角函数等等),它是一个数学工具类不需要创建对象(因此构造器私有化)。

  • 使用:Math中许多成员都被static修饰了,直接用类名.xxx调用即可。

image-20220630083745346


4. System类

System的功能是通用的,都是直接用类名调用即可,所以System不能被实例化。

System类常用方法:

方法名说明
public static void exit(int status)终止当前运行的Java虚拟机,非零表示异常终止
public static native long currentTimeMillis()返回当前系统时间的毫秒数(时间戳)
public static void arraycopy(源数组,起始索引,目标数组,起始索引,拷贝个数)数组拷贝

5. BigDecimal类

用于解决浮点型运算精度丢失问题。

image-20220630085816933

使用方式: 创建BigDecimal对象封装浮点类型数据 (通过valueOf方法创建)

public static BigDecimal valueOf(double val) 

BigDecimal类常用API:

方法名说明
public BigDecimal add(BigDecimal b)加法
public BigDecimal subract(BigDecimal b)减法
public BigDecimal multiply(BigDecimal b)乘法
public BigDecimal divide(BigDecimal b)除法

6. 日期与时间

6.1 Date

  • Date类的对象可以获取系统当前的日期时间。

  • 它在java.util包下。

1、Date类的构造器:

// 创建一个Date对象,代表的是系统当前的日期时间(精确到毫秒)
public Date() 

2、Date类常用方法:

// 获取时间对象的毫秒值
public long getTime()
image-20220630182007693

3、时间毫秒值->日期对象:

// 有参构造器
public Date(long time) // 把时间毫秒值转换成Date日期对象
// 设置日期对象的时间,参数为时间毫秒值
public void setTime(long time)

示例:计算当前时间往后走1小时121秒之后的时间是多少?

public class DateTest2 {
    public static void main(String[] args) {
        // 获取当前系统时间的毫秒值
        long time = System.currentTimeMillis();
        System.out.println("当前时间为:");
        System.out.println(new Date(time));
        time += (60 * 60 + 121) * 1000;
        System.out.println("当前时间往后走1小时121秒之后的时间是:");
        System.out.println(new Date(time));
    }
}
image-20220630183745038

6.2 SimpleDateFormat

  • SimpleDateFormat可以把Date对象或毫秒值格式化成我们喜欢的时间形式。
  • 也可以把字符串的时间形式解析成日期对象。
格式化:
		Date对象  ->  2022年6月30日 18:40
        时间毫秒值 ->  2022年6月30日 18:40   
        
解析:	   2022年6月30日 18:40 -> Date对象

1、SimpleDateFormat的构造器:

构造器说明
public SimpleDateFormat()构造一个SimpleDateFormat对象,使用默认格式
public SimpleDateFormat(String pattern)构造一个SimpleDateFormat对象,使用指定的格式

2、SimpleDateFormat的格式化方法:

构造器说明
public final String format(Date date)将日期对象格式化成日期/时间字符串
public final String format(Object time)将时间毫秒值格式化成日期/时间字符串
  • 被final修饰的方法不能被重写。

格式化的时间格式:

: y
月: M: d
时: H: m
秒: s
    
完整格式:yyyy-MM-dd HH:mm:ss (2022-6-30 19:04:30)  

image-20220630190809853

3、SimpleDateFormat解析字符串时间并返回日期对象:

解析方法说明
public Date parse(String source)从给定字符串的开始解析文本来生成日期

示例:计算出2022年06月30日 19点06分55秒,往后走2天14小时49分06秒后的时间是多少。

public class SimpleDateFormatTest2 {
    public static void main(String[] args) throws ParseException {
        // 1、定义字符串时间
        String dateStr = "2022年06月30日 19点06分55秒";

        // 2、将字符串时间解析成日期对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH点mm分ss秒");
        Date date = sdf.parse(dateStr);

        // 3、将时间毫秒值往后走2天14小时49分06秒
        long time = date.getTime() + (24 * 60 * 60 * 2L + 14 * 60 * 60 + 49 * 60 + 6) * 1000;
        
        // 4、格式化结果
        dateStr = sdf.format(time);
        System.out.println(dateStr); // 2022年07月03日 09点56分01秒
    }
}

6.3 Calendar

  • Calendar代表系统此刻日期对应的日历对象。
  • Calendar是一个抽象类,不能直接创建对象。

image-20220630193701451

// 通过方法获取实例(多态)
public static Calendar getlnstance()

常用方法:

方法名说明
public int get(int field)获取日期中的某个字段信息
public void set(int field, int value)修改日历的某个字段
public void add(int field, int amount)为某个字段添加/减少指定的值
public final Date getTime()拿到此刻日期对象
public long getTimeInMillis()拿到此刻时间毫秒值

注意:Calendar是可变日期对象,一旦修改后会其对象本身表示的时间会发生变化。


示例:Calendar的使用

// 获取的操作用的多
public class CalendarTest {
    public static void main(String[] args) {
        // 1、拿到系统此刻的日历对象
        Calendar cal = Calendar.getInstance();
        //System.out.println(cal);
        /*
            字段对应的数据:
            java.util.GregorianCalendar[
                time=1656591237954,
                areFieldsSet=true,
                areAllFieldsSet=true,
                lenient=true,
                zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null],
                firstDayOfWeek=1,
                minimalDaysInFirstWeek=1,
                ERA=1,
                YEAR=2022,
                MONTH=5,
                WEEK_OF_YEAR=27,
                WEEK_OF_MONTH=5,
                DAY_OF_MONTH=30,
                DAY_OF_YEAR=181,
                DAY_OF_WEEK=5,
                DAY_OF_WEEK_IN_MONTH=5,
                AM_PM=1,HOUR=8,
                HOUR_OF_DAY=20,
                MINUTE=13,
                SECOND=57,
                MILLISECOND=954,
                ZONE_OFFSET=28800000,
                DST_OFFSET=0]
         */

        // 2、获取日历的信息
        int year = cal.get(Calendar.YEAR);
        System.out.println("year = " + year);
        int month = cal.get(Calendar.MONTH + 1);
        System.out.println("month = " + month);// 它从0开始
        int days = cal.get(Calendar.DAY_OF_YEAR);
        System.out.println("今年已将过去" + days+"天"); //今年已将过去181天

        // 3、public void set(int field, int value):修改日历某个字段信息,通常不修改
        // 修改年
        // cal.set(Calendar.YEAR,2023);
        // System.out.println("修改之后的年份为:"+cal.get(Calendar.YEAR));

        // 4、public void add(int field, int amount):为某个字段添加/减少指定的值
        // 64天后是什么时间
        cal.add(Calendar.DAY_OF_YEAR,64);


        // 5、public final Date getTime():拿到此刻日期对象,不常用
        Date date = cal.getTime();
        System.out.println("date="+date);//date=Fri Sep 02 20:29:53 CST 2022

        // 6、public long getTimeInMillis():拿到此刻时间毫秒值,不常用
        System.out.println(cal.getTimeInMillis()); //1662121793001
    }
}

7. JDK8 新增的日期类

image-20220701163550057

7.1 LocalDate、LocalTime、LocalDateTime

  • LocalDate、LocalTime、LocalDateTime:他们分别表示日期,时间,日期时间对象,他们的类的实例是不可变的对象。
  • 他们三者构建对象和API都是通用的。
image-20220701171612694 image-20220701171209726 image-20220701171245035

7.2 Instant(时间戳)

image-20220701172054491


7.3 DateTimeFormatter

image-20220701172354054

7.4 Duration、Period

image-20220701172609214
image-20220701172751676
  • Duration: 用于计算两个 “时间” 间隔。

  • Period: 用于计算两个 “日期” 间隔。


7.5 ChronoUnit

image-20220701173055761

8. 包装类

包装类是Java提供的一组类,专门用来创建8种基本数据类型对应的对象,一共8个包装类,存放在 java.lang包。

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

8.1 为什么要有包装类?

  • Java为了万物皆对象,为8种基本类型提供了对应的包装类。
  • 集合和泛型不支持基本数据类型,只能支持包装类型。

包装类体系结构如下:

img

示例:

public class IntegerDemo {
    public static void main(String[] args) {
        // 定义一个字符串
        String str = "123";
        // 将字符串转换成整型
        int num = Integer.parseInt(str);
        System.out.println(num++); // 123
    }
}

8.2 自动装箱和拆箱

  • 装箱:将基本数据类型转为对应的包装类对象,利用各个包装类的构造方法完成。
  • 拆箱:将包装类对象转为对应的基本数据类型,利用Number类的xxxValue()方法完成(xxx表示基本数据类型的名称)。
  • JDK1.5之前,使用手动方式进行装箱和拆箱的操作。
  • JDK1.5之后,使用**自动装箱(Autoboxing)自动拆箱(Auto Unboxing)**的操作。(所以我们使用的便利是拿编译器的辛苦换来的🤭)

示例:

public class TestBoxingAndUnboxing {
    public static void main(String[] args) {
        // 1、基本数据类型变为包装类,装箱
        // 通过传入基本类型数据,然后使用new关键字调用Integer类的构造方法,将其变为Integer类的对象intObj,整个过程为装箱操作。
        Integer intObj = new Integer(10);
        // 2、包装类变为基本类型,拆箱
        // 将包装类Integer类的对象intObj,还原为基本类型,并赋值给整型变量temp,整个过程为拆箱操作。
        int temp = intObj.intValue();
        System.out.println("整型变量temp的值为:" + temp);

        System.out.println("---------------分割线-----------------");

        int temp2 = 345;
        // 3、自动装箱
        //在编译阶段,编译器会自动将 intObj = temp2;  这条语句扩转为:intObj = intObj.valueOf(temp2);
        intObj = temp2;
        // 4、自动拆箱
        //在编译阶段,编译器会自动将  int temp3 = intObj;  这条语句扩转为: int temp3 = intObj.intValue();
        int temp3 = intObj;
        temp3++;
        System.out.println("整型变量temp3的值为:" + temp3);

        // 自动装箱
        Boolean boo = true;
        // 自动拆箱
        boolean flag = boo;
        System.out.println(flag && false);
    }
}

img


8.3 基本类型与字符串的转换

使用包装类的特点是将字符串变为指定的基本类型数据。

  • 以Integer为例: public static int parseInt(String s);
  • 以Double为例: public static int parseDouble(String s);
  • 以Boolean为例: public static int parseBoolean(String s);

但是以上的操作方法形式对于字符类型(character)是不存在的。因为String类有一个charAt()方法,可以取得指定索引的字符。

示例:

public class Test3 {
    public static void main(String[] args) {
        // 定义一个字符串
        String str = "3.14";
        // 将字符串转为double
        double d = Double.parseDouble(str);
        System.out.println("d:" + d);

        //重新给字符串赋值
        str = "true";
        boolean flag = Boolean.parseBoolean(str);
        if (flag){
            System.out.println("条件满足!");
        }else{
            System.out.println("条件不满足!");
        }
    }
}

运行结果如下:
在这里插入图片描述


8.4 将基本类型变为字符串

  • 使用String类中的valueOf()方法。

  • 或者拼接字符串,str+“”。

示例:

public class Test3 {
    public static void main(String[] args) {
     int intValue = 100;
        // 将整型变量转换成字符串型
        String str = String.valueOf(intValue);
        System.out.println(str);

        double e = 2.718;
        // 将double变量转换成字符串型
        str = String.valueOf(e);
        System.out.println(str);
    }
}

运行结果如下:
在这里插入图片描述


8.5 Integer数值比较

public class Test {
    public static void main(String[] args) {
    	// 自动装箱,相当于 Integer.valueOf();
        Integer a = 200;
        Integer b = 200;
        Integer c = 100;
        Integer d = 100;
        int e = 200;
        System.out.println(a == b); // false
        System.out.println(c == d); // true
        // 先自动拆箱相当于Integer.intValue();,然后再判断是否相等
        System.out.println(b == e); // true
    }
}

如果整型字面量的值在-128 到 127 之间,那么不会 new 新的 Integer 对象,而是直接引用常量池
中的 Integer 对象,所以 c = = d 的结果是 true,而 a = = b 的结果是 false。


9. 正则表达式

正则表达式可以用一些规定的字符来制定规则,并用来校验数据格式的合法性。例如:表单验证等等

需求:校验一个QQ号码是否正确,6位或20位号之内必须全部是数字

public class RegexDemo1 {
    public static void main(String[] args) {
        // System.out.println(check1("1234567889"));
        // System.out.println(check1("123456a7889"));

        // 使用正则表达式校验
        System.out.println(check2("1234567889"));
    }

    /**
     * 常规写法
     *
     * @param qq
     * @return
     */
    public static boolean check1(String qq) {
        // 1、判断qq长度是否满足要求
        if (qq == null || qq.length() < 6 || qq.length() > 20) {
            return false;
        }
        //2、使用循环遍历每个字符,然后判断qq中是否全部是数字
        for (int i = 0; i < qq.length(); i++) {
            char ch = qq.charAt(i);
            // 非数字判断
            if (ch < '0' || ch > '9') {
                return false;
            }
        }
        return true;
    }


    /**
     * 使用正则表达式校验
     *
     * @param qq
     * @return
     */
    public static boolean check2(String qq) {
        /*
                \d 表示全部是数字
                \\ 转义字符  ->  \
                {6,20} 表示[6,20]之间的数
         */
        return qq != null && qq.matches("\\d{6,20}");

    }
}

9.1 正则表达式的匹配规则

java.util.regex.Pattern匹配规则类

1、字符类(默认匹配一个字符)

[abc]           只能是a、b或者c    
[^abc]          除了a、b、c之外的任何字符  
[a-zA-Z]        a到z或AZ 之间的字符  
    
[a-d[m-p]]      a到d或m到p:[a-dm-p](并集) 
[a-z&&[def]]    d、e或f(交集) 
[a-z&&[^bc]]    a到z,除了b和c:[ad-z](减法) 
[a-z&&[^m-p]]   a到z,而非m到 p:[a-lq-z](减法)     

2、预定义的字符类(默认匹配一个字符)

.       任何字符(与行结束符可能匹配也可能不匹配) 
\d      一个数字:[0-9] 
\D      非数字: [^0-9] 
\s      一个空白字符:[ \t\n\x0B\f\r] 
\S      非空白字符:[^\s] 
\w      单词字符(英文、数字、下划线)[a-zA-Z_0-9] 
\W      一个非单词字符:[^\w] 

3、贪婪的量词(配合匹配多个字符)

X?          X,一次或一次也没有 
X*          X,零次或多次 
X+          X,一次或多次 
X{n}        X,正好 n 次 
X{n,}       X,至少 n 次 
X{n,m}      X,至少 n 次,但是不超过 m 次 

4、String类的matches()方法可以与正则表达式进行匹配。

// 判断是否匹配正则表达式,匹配返回true,不匹配返回false。
public boolean matches(String regex)

image-20220701090204845

示例:

System.out.print1n("a".matches("[abc]"));    // true
System.out.println("z".matches("[abc]"));    // false
System.out.print1n("ab".matches( "[abc]")); // falre,只能匹配一个
System.out.print1n("ab".matches("[abc ]+")); // true

9.2 正则表达式的常见案例

1、请编写程序模拟用户输入手机号码、验证格式正确,并给出提示,直到格式输入正确为止。

public class RegexPhone {
    public static void main(String[] args) {
        check();
    }

    public static void check() {
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入你注册的手机号码:");
            String phone = sc.next();
            // 判断手机号码格式是否正确,1开头,第二位3-9,之后九位没有要求
            if(phone.matches("1[3-9]\\d{9}")){
                System.out.println("手机号码格式正确,注册完成~");
                break;
            }else {
                System.out.println("格式有误!");

            }
        }
    }
}

2、请编写程序模拟用户输入邮箱号码、验证格式正确,并给出提示,直到格式输入正确为止。

public class RegexEmail {
    public static void main(String[] args) {
        check();
    }

    public static void check() {
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入你注册的邮箱:");
            String email = sc.next();
            /*
                1433123335@qq.com
                \\w{1,30} 用户名
                @[a-zA-Z0-9]{2,20} @xxx
                \\.  ->   .
                ([a-zA-Z]{2,20}){1,2} 有可能一级域名或者两级域名

             */
            if(email.matches("\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-zA-Z]{2,20}){1,2}")){
                System.out.println("邮箱格式正确,注册完成~");
                break;
            }else {
                System.out.println("格式有误!");

            }
        }
    }
}

3、请编写程序模拟用户输入电话号码、验证格式正确,并给出提示,直到格式输入正确为止。

public class RegexPhone {
    public static void main(String[] args) {
        check();
    }

    public static void check() {
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入你的电话号码:");
            String phone = sc.next();
           
            if(phone.matches("0\\d{2,6}-?\\d{5,20}")){
                System.out.println("格式正确,注册完成~");
                break;
            }else {
                System.out.println("格式有误!");

            }
        }
    }
}

9.3 正则表达式在方法中的应用

正则表达式在字符串方法中的使用:

方法名说明
public String replaceAll(String regex,String newStr)按照正则表达式匹配的内容进行替换
public String sptit(String regex)按照正则表达式匹配的内容进行分割字符串,并返回一个字符串数组。

9.4 正则表达式爬取信息

/**
 * 需求:从下面信息解析电话号和邮箱
 *
 * @author 白豆五
 * @version 2022/7/1 14:25
 * @since JDK8
 */
public class RegexContent {
    public static void main(String[] args) {
        // 1、编写字符串数据
        String rs = "来黑马程序学习Java,电话020-43422424,或者联系邮箱" +
                "itcast@itcast.cn,电话18762832633,0203232323" +
                "邮箱bozai@itcast.cn,400-100-3233 , 4001003232";

        // 2、定义爬取规则
        /*
            邮箱:   \w{1,}@\w{2,10}(\.\w{2,10}){1,2}
            手机号: 1[3-9]\d{9}
            电话号: 1[3-9]\d{9} , 400-?\d{3,8}-?\d{3,8}
         */
        String regex = "(\\w{1,}@\\w{2,10}(\\.\\w{2,10}){1,2})|" +
                "(1[3-9]\\d{9})|(0\\d{2,5}-?\\d{5,15})|(400-?\\d{3,8}-?\\d{3,8})";


        // 3、编译正则表达式后返回一个匹配规则对象
        Pattern pattern = Pattern.compile(regex);

        // 4、获取匹配器对象
        Matcher matcher = pattern.matcher(rs);

        // 5、通过匹配器去内容中爬取信息
        while (matcher.find()){
            System.out.println(matcher.group());
        }
    }
}

10. Arrays类

java.util. Arrays数组操作工具类,专门用于操作数组元素。

Arrays类常用API:

方法名说明
public static String toString(数据类型[] a)返回数组中的内容
public static void sort(数据类型[] a)对数据进行排序(默认升序)
public static void sort(数据类型[] a, Comparator<? super T> c)使用比较器对熊自定义排序
public static int binarySearch(int[]a, int key)二分搜索数组中的数据,存在返回索引,不存在返回-1

拷贝数组:System.arraycopy()比Arrays.copyOf()更高效。

11. 常见算法

11.1 选择排序

思想:每轮选择当前的位置,开始找出后面较小值与该位置交换。

image-20220701152447114

选择排序的关键步骤:

  • 确定总共需要选择几轮:数组的长度-1。
  • 控制每轮以当前位置为基础,与后面元素进行比较。
public class SelectionSort {
    public static void main(String[] args) {
        // 1、定义数组
        int[] arr = {5, 1, 3, 2};
        // 2、定义一个循环,控制选择几轮 arr.length - 1
        for (int i = 0; i < arr.length - 1; i++) {
            // 定义内部循环,控制内部选择几次
            for (int j = i + 1; j < arr.length; j++) {
                // 当前位 arr[i]
                // 如果后面的数据比当前位的数据还小,则交换
                if (arr[i] > arr[j]) {
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));

    }
}

11.2 二分查找

  • 基本查找:从前往后逐个比较元素,效率低。

  • 二分查也叫对半查找,它的性能更好,二分查找的前提是数组必须是排好序的。

  • 二分查询相当于每次去掉一半的查找范围。

image-20220701160613460

实现步骤:

1、定义变量记录左边和右边的位置。

2、使用while循环控制查找(条件左边位置<=右边位置)。

3、循环内部获取中间元素索引。

4、判断当前要找的元素如果大于中间元素,左边位置=中间索引+1。

5、判断当前要找的元素如果小于中间元素,右边位置=中间索引-1。

6、判断当前要找的元素如果等于中间元素,返回当前中间元素索引。

public class BinarySearch {
    public static void main(String[] args) {

        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        System.out.println(binarySearch(arr,30));
    }

    /**
     * 二分查找算法的实现
     *
     * @param arr  排序的数组
     * @param data 要找的数据
     * @return 索引,如果元素不存在返回-1
     */
    public static int binarySearch(int[] arr, int data) {
        // 1、定义左边位置和右边位置
        int left = 0;
        int right = arr.length - 1;
        //  2、循环折半查询
        while (left <= right) {
            // 取中间索引
            int middleIndex = (left + right) / 2;
            // 3、判断data是否大于中间元素
            if (data > arr[middleIndex]) {
                //往右边找
                left = middleIndex + 1;
            }else if(data<arr[middleIndex]){
                //往左边找
                right=middleIndex-1;
            }else {
                return middleIndex;
            }
        }
        return -1;
    }
}

12. Lambda表达式

Java8是Java语言自JDK1.5以后的一个重大的里程碑版本,因为它增加了很多新特性,这些新特性会改变编程的风格和解决问题的方式。

例如:日期时间API、Lambda表达式、Stream API(操作集合)、方法引用、CompletableFuture(异步编程)等。

Lambda表达式的作用:简化匿名内部类的写法。

12.1 函数式编程思想

之前我们写的代码都是面向对象的编程思想,该思想强调的是通过对象来做事情。例如 我们想要线程执行任务就必须创建一个实现Runnable接口的实现类对象,但是我们真正要做的事情实际上就是执行run方法中的代码从而来执行线程的任务。

函数式编程思想省略了创建对象的复杂语法,然后通过 lambda表达式 直接传递代码来执行线程任务。而不需要创建 Runnable接口的实现类对象。

函数式编程思想强调的是做什么,而不是以什么方式去做。

面向对象编程和函数式编程两种编程风格的对比:(函数式编程相比oop语法更加整洁)

package com.baidou.java.jdk.feature.java8;

/**
 * Lambda表达式的使用
 *
 * @author baidou 1433021114@qq.com
 * @version 2022/6/5 14:14
 * @since JDK8
 */
public class LambdaExpressionTest {
    public static void main(String[] args) {
        new LambdaExpressionTest().testLambdaExpression();
    }


    /**
     * 面向对象编程和函数式编程两种编程风格的对比
     */
    public void testLambdaExpression() {
        // 面向对象的方式创建和启动线程
        new Thread(new CustomRunnable()).start();

        // 函数式编程方式创建和启动线程
        new Thread(()->{
            System.out.println("2.函数式编程方式创建和启动线程");
        }).start();
    }

}

/**
 * 定义一个类实现Runnable接口
 */
class CustomRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("1.面向对象的方式创建和启动线程");
    }
}

12.2 函数式接口

函数式接口表示接口中只有一个抽象方法,而且用注解@FunctionalInterface标记的接口就是函数式接口。

这里需要注意的是,接口中如果有其他的方法(默认方法、静态方法),但是只有一个抽象方法,它也是函数式接口,例如java.util.Comparator接口。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

自定义函数式接口:

package com.baidou.java.jdk.feature.java8;

/**
 * 自定义函数式接口
 *
 * @author baidou 1433021114@qq.com
 * @version 2022/6/5 14:56
 * @since JDK8
 */
@FunctionalInterface
public interface CustomFunctionalInterface {
    // 实现两个整数相加
    int add(int a, int b);
}

12.3 Lambda表达式的使用

要想使用Lambda表达式必需先有函数式接口,Lambda表达式也是函数式编程思想的体现。

Lambda表达式的语法格式

1、Lambda表达式的标准语法格式

()->{}    

解释: () 表示重写函数式接口的抽象方法的参数列表
     -> 表示lambda表达式的固定组成部分,箭头表示它指向什么
     {} 表示重写函数式接口的抽象方法的方法体,也是方法要做的事情
/**
 * lambda表达式的完整格式使用
 */
@Test
public void testColloectionsSort() {
    List<Integer> list = new ArrayList<>();
    list.add(77);
    list.add(66);
    list.add(11);
    list.add(22);
    list.add(55);
    list.add(1024);
    // 使用匿名内部类降序排序
    Collections.sort(list, new Comparator<Integer>() {
        @Override
        public int compare(Integer value1, Integer value2) {
            return value2 - value1;
        }

    });
    System.out.println("使用匿名内部类降序排序list集合的结果是" + list);

    // 使用lambda表达式降序排序
    Collections.sort(list, (Integer value1, Integer value2) -> {
        return value2 - value1;
    });
    System.out.println("使用lambda表达式降序排序list集合的结果是" + list);
}

2、Lambda表达式的简化语法格式

简化之前:

// 使用lambda表达式降序排序
Collections.sort(list, (Integer value1, Integer value2) -> {
    return value2 - value1;
});
  • 参数的数据类型可以不写;
  • {}中如果只有一条执行语句,{}; 以及 return 都可以不写。(三个必须一起省略)

简化之后:

Collections.sort(list, (value1,value2) -> value2 - value1);

Lambda表达式的应用场景


1、变量(使用极少)

package com.baidou.java.jdk.feature.java8;

/**
 * 自定义函数式接口
 *
 * @author baidou 1433021114@qq.com
 * @version 2022/6/5 14:56
 * @since JDK8
 */
@FunctionalInterface
public interface CustomFunctionalInterface {
    // 实现两个整数相加
    int add(int a, int b);
}
/**
 * lambda表达式的应用场景
 */
@Test
public void testLambdaExpressionUsage() {
    // 将lambda表达式赋值给一个变量
    CustomFunctionalInterface c = (int a, int b) -> {
        return a + b;
    };
    int result = c.add(12, 34);
    System.out.println("result = " + result);
}

2、方法的参数

Collections.sort(list, (value1,value2) -> value2 - value1);

3、方法的返回值

/**
 * lambda表达式可以作为方法的返回值
 */
public CustomFunctionalInterface getCustomFunctionalInterface(){
    return (int a,int b)->{return a+b;};
}
CustomFunctionalInterface c = getCustomFunctionalInterface();
System.out.println("result = " + c.add(11, 22));

13、Stream流

13.1 什么是Stream流?

  • 在Java8中,得益于Lambda所带来的函数式编程,引入了一个全新的概念:Stream流。

  • 作用:简化了操作集合和数组的API,结合lambda表达式。


Stream流的思想和使用步骤:

1.先得到集合或者数组的Stream流(Stream流相当于一根传送带)
2.把元素放上去。
3.然后就用这个Stream流简化的API来方便的操作元素。


13.2 Stream流的获取

Stream操作集合或者数组的第一步是先得到stream流,然后才能使用流的功能。

1、集合获取Stream流的方式:

集合获取Stream的方式是通过调用stream()方法实现的。

名称说明
default Stream stream()获取当前集合对象的stream流

2、数组获取Stream流的方式:

名称说明
public static Stream stream(T[ ] array)获取当前数组的Stream流
public static Stream of(T… vilues)获取当前数组/可变数据的stream流

示例:

// Collection集合获取Stream流
Collection<String> list = new ArrayList<>();
Stream<String> s = list.stream();

// Map集合获取Stream流
Map<String, Integer> maps = new HashMap<>();
Stream<String> keyStream = maps.keySet().stream();//键流
Stream<Integer> valueStream = maps.values().stream();//值流
Stream<Map.Entry<String, Integer>> keyAndValueStream = maps.entrySet().stream(); // 键值对流(整体)

// 数组获取Stream流
IntStream arrayStream1 = Arrays.stream(new int[]{11, 2, 3, 4, 5});
Stream<int[]> arrayStream2 = Stream.of(new int[]{11, 2, 3, 4, 5});

13.3 Stream流常用API(中间操作方法)

image-20220706055950920

  • filter:过滤元素(过滤条件)
  • forEach:遍历
  • count:统计个数,返回值long类型。
  • limit:取前几个元素
  • skip:跳过前几个元素
  • map:加工方法
  • concat:合并流
  • distinct:去重复
public class StreamDemo2 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("张珍珍");
        list.add("赵六");
        list.add("陈七");
        list.add("张火火");

        /*
           filter:对流中的数据进行过滤
           Stream<T> filter(Predicate<? super T> predicate);
         */
        // list.stream().filter(new Predicate<String>() {
        //     @Override
        //     public boolean test(String s) {
        //         return s.startsWith("张"); //保留姓张的数据
        //     }
        // }).forEach(new Consumer<String>() {
        //     @Override
        //     public void accept(String s) {
        //         System.out.println(s);
        //     }
        // });
        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));

        /*
            count:统计个数
         */
        long count = list.stream().filter(s -> s.length() == 3).count();
        System.out.println("count = " + count);

        /*
            limit():取前几个元素
         */
        // list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(s -> System.out.println(s));
        list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(System.out::println);


        /*
            skip():跳过前几个元素
         */
        list.stream().filter(s -> s.startsWith("张")).skip(2).forEach(s -> System.out.println(s));

        /*
            map加工方法
            map(new Function<原材料类型, 加工后的结果类型>())
         */
        // 给集合前面都加上hello
        list.stream().map(s -> "hello" + s).forEach(s -> System.out.println(s));
        // 把所有名称都加工成一个学生对象
        // list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));
        list.stream().map(Student::new).forEach(System.out::println);


        /*
            concat:合并流
            不同类型流用Object接
         */
        Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
        Stream<String> s2 = Stream.of("Java","PHP","C++","Go");
        Stream<String> s3= Stream.concat(s1,s2);
        s3.forEach(System.out::println);
    }
}


class Student {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

注意事项:

  • 中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程。

  • 在Stream流中无法直接修改集合、数组中的数据。


13.4 Stream流常见的终结操作方法

image-20220706065844336

注意:终结操作方法,调用完成之后流就无法继续使用了,原因是它不会返回Stream流。


小结: 终结方法和非终结方法的含义?

调用终结方法后流不可以继续使用,调用非终结方法会返回新的流,支持链式编程。


13.5 Stream流的收集

用Stream流操作集合、数组,操作的结果数据恢复到集合或者数组中去。

image-20220706071614158


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1014502.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python入门教程39:教你使用distutils本地发布模块与模块安装的操作

★★★★★博文创作不易&#xff0c;我的博文不需要打赏&#xff0c;也不需要知识付费&#xff0c;可以白嫖学习编程小技巧。使用代码的过程中&#xff0c;如有疑问的地方&#xff0c;欢迎大家指正留言交流。喜欢的老铁可以多多点赞收藏分享置顶&#xff0c;小红牛在此表示感谢…

RabbitMQ消息可靠性(一)-- 生产者消息确认

前言 在项目中&#xff0c;引入了RabbitMQ这一中间件&#xff0c;必然也需要在业务中增加对数据安全性的一层考虑&#xff0c;来保证RabbitMQ消息的可靠性&#xff0c;否则一个个消息丢失可能导致整个业务的数据出现不一致等问题&#xff0c;对系统带来巨大的影响&#xff0c;…

tomcat架构概览

https://blog.csdn.net/ldw201510803006/article/details/119880100 前言 Tomcat 要实现 2 个核心功能&#xff1a; 处理 Socket 连接&#xff0c;负责网络字节流与 Request 和 Response 对象的转化。加载和管理 Servlet&#xff0c;以及具体处理 Request 请求。 因此 Tomc…

weblogic __ 10.3.6 __ 反序列化漏洞 _ CVE-2017-10271

weblogic __ 10.3.6 __ 反序列化漏洞 _ CVE-2017-10271 说明内容漏洞编号CVE-2017-10271漏洞名称反序列化漏洞影响范围10.3.6.0.0&#xff0c;12.1.3.0.0&#xff0c;12.2.1.1.0&#xff0c;12.2.1.2.0漏洞描述Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其…

MySQL里的查看操作

查看数据库或者表 列出所有数据库&#xff1a; show databases;查看正在使用的数据库&#xff08;必须大写&#xff09;&#xff1a; SELECT DATABASE();列出数据库中的表&#xff1a; use 数据库;//选中数据库 show 表;//列出当前数据库下所有表获取数据库表结构&#xff…

OpenCV(四十七):RANSAC优化特征点匹配

1.RANSAC算法介绍 RANSAC是一种常用的参数估计方法&#xff0c;全称为Random Sample Consensus&#xff08;随机抽样一致性&#xff09;。它的主要思想是通过随机选择一部分数据样本&#xff0c;构建模型并评估其拟合程度&#xff0c;迭代过程中逐步优化模型&#xff0c;最终得…

Linux知识点 -- 网络基础(二)

Linux知识点 – 网络基础&#xff08;二&#xff09;&#xff08;1&#xff09; 文章目录 Linux知识点 -- 网络基础&#xff08;二&#xff09;&#xff08;1&#xff09;一、使用协议来实现一个网络版的计算器1.自定义协议2.守护进程3.使用json来完成序列化 二、HTTP协议1.概念…

Redis 事务实现原理

1. 什么是Redis事务 提到事务,我们可能马上会想到传统的关系型数据库中的事务,客户端首先向服务器发送BEGIN开启事务,然后执行读写操作,最后用户发送 COMMIT 或者 ROLLBACK 来提交或者回滚之前的操作。 但是Redis中的事务与关系型数据库是不一样的,Redis 通过 MULTI 命令开始…

GB28181学习(四)——网络设备信息查询

要求 源设备向目标设备发送信息查询命令&#xff0c;目标设备将结果通过查询应答命令返回给源设备&#xff1b;设备信息查询命令包括&#xff1a; 设备目录设备信息设备状态信息设备配置预置位、看守位巡航轨迹列表巡航轨迹PTZ精准状态存储卡状态等 信息查询的范围&#xff1a…

内网穿透对开发人员有什么作用?要怎么实现?快解析

在当今快节奏的互联网时代&#xff0c;软件开发人员需要时刻与内外部服务器进行通信和调试&#xff0c;只有这样才能带来良好的工作速度&#xff0c;顺利推动项目的进展。然而&#xff0c;由于受到网络环境的限制&#xff0c;有时候我们可能无法直接访问公司内网的服务器&#…

差分方程模型:蛛网模型

在完全竞争的市场经济中&#xff0c;一个时期某种消费品如猪肉的上市量远远大于需求量&#xff0c;由于销售不畅导致价格下降&#xff0c;生产者发现养猪赔钱&#xff0c;于是转而经营其它农副产品。过一段时间猪肉上市量就会下降&#xff0c;此时供不应求导致价格上涨&#xf…

【MySQL】MySQL索引的定义、分类、Explain、索引失效和优化

索引的介绍 索引是帮助MySQL高效获取数据的数据结构 MySQL在存储数据之外&#xff0c;数据库系统中还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种引用(指向)表中的数据&#xff0c;这样我们就可以通过数据结构上实现的高级查找算法来快速找到我们想要的数…

设计原则SOLID看这一篇就够了

文章目录 1.引言1.1. 背景1.2. 简要介绍 SOLID 原则1.1. 面向对象编程和设计的重要性 2. 单一职责原则&#xff08;SRP&#xff09;2.1. 定义和原理2.2. SRP 的好处与目标2.3. 例子和代码展示2.4. 如何识别和解决 SRP 原则的违反2.5. 注意事项和局限性 3. 开闭原则&#xff08;…

Centos7.9 一键脚本部署 LibreNMS 网络监控系统

前言&#xff1a; LibreNMS 是个以 PHP/MySQL 为基底的自动探索网络监控系统 LibreNMS 官网 版本23.8.2-52-g7bbe0a2 - Thu Sep 14 2023 22:33:23 GMT0700数据库纲要2023_09_01_084057_application_new_defaults (259)Web 服务器nginx/1.20.1PHP8.1.23Python3.6.8DatabaseMa…

Killer!永久禁用WindowsDefender

工具介绍 WinDefenderKiller&#xff0c;使用C写的通过注册表项永久禁用Windows Defende的一个工具。 关注【Hack分享吧】公众号&#xff0c;回复关键字【230726】获取下载链接 编译使用 执行以下命令编译&#xff1a; # x86_64-w64-mingw32-g -O2 disableWinDef.cpp -o win…

JS 原型和原型链

原型和原型链 1. 了解原型和原型链1.1 原型1.2 原型链 2. 原型2.1 prototype2.2 __proto__ 隐式原型 3. 原型链 1. 了解原型和原型链 1.1 原型 原型&#xff1a; prototype 又称显示原型 1、原型是一个普通对象 2、只有构造函数才具备该属性 3、公有属性可操作 1.2 原型链 原…

数据治理-元数据管理-元数据类型

定义 元数据&#xff0c;定义和描述其它数据的数据。 类型 业务元数据、技术元数据和操作元数据。在图书馆或信息科学中&#xff0c;可分为描述元数据、结构元数据、管理元数据。 业务元数据 主要关注数据的内容和条件&#xff0c;另包括与数据治理相关的详细信息。业务元数据…

logback异步appender日志源码详解

背景&#xff1a; 日常打印日志时&#xff0c;使用logback的异步写日志几乎是标准的配置方式&#xff0c;本文从源码上看看异步写日志的整个流程 异步Appender日志 一般日志的配置如下所示 appender(“ASYNC-LOG”, AsyncAppender) { neverBlock true queueSize 10000 } 这…

前端需要知道的计算机网络知识----网络安全,自学网络安全,学习路线图必不可少,【282G】初级网络安全学习资源分享!

网络安全&#xff08;英语&#xff1a;network security&#xff09;包含网络设备安全、网络信息安全、网络软件安全。 黑客通过基于网络的入侵来达到窃取敏感信息的目的&#xff0c;也有人以基于网络的攻击见长&#xff0c;被人收买通过网络来攻击商业竞争对手企业&#xff0c…

CH07_封装

封装记录&#xff08;Encapsulate Record | 162&#xff09; 曾用名&#xff1a;以数据类代替记录&#xff08;Replace Record with Data Class&#xff09; organization {name: "Acme Gooseberries", country: "GB"};class Organization {constructor(…