Bootstrap

Java进阶(五)常用API、Lambda、常见算法

五、常用API、Lambda、常见算法

需要学会什么:

  • 如何处理时间:在程序中经常需要处理时间、获取时间、时间判断、运算等。
  • 认识包装类:Java认为一切皆对象,8种基本类型不是,如何实现的,集合、泛型也不支持基本类型,怎么解决?
  • 正则表达式:程序中需要对各种信息进行格式合法性的校验,如手机号码,邮箱等。
  • 经常需要操作数组元素:如何快捷操作数组元素,如输出数组内容、排序、元素搜索等。排序和搜索算法是什么样的?
  • Lambda表达式:匿名内部类的代码是可以进一步的简化的,什么情况下可以简化,需要用什么知识完成?

1.日期与时间

a.Date

Date类概述:

  • Date类的对象在Java中代表的是当前所在系统的此刻日期时间。

Date的构造器:

名称

说明

public Date()

创建一个Date对象,代表的是系统当前此刻日期时间。

public Date(long time)

把时间毫秒值转化成Date日期对象。

Date的常用方法:

名称

说明

public long getTime()

获取时间对象的毫秒值。

public void setTime(long time)

设置日期对象的时间为当前时间毫秒值对应的时间。

Date类记录时间的2种形式:

  • 形式一:日期对象。

            Date date = new Date();
            System.out.println(date);
    
  • 形式二:时间毫秒值。

            Date date = new Date();
            long time = date.getTime();
            System.out.println(time);
    
            long time1 = System.currentTimeMillis();
            System.out.println(time1);
    

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

Test.java

import java.util.Date;

public class Test {
    public static void main(String[] args) {
        // 获取当前系统时间戳
        long current_date = System.currentTimeMillis();
        current_date += (60 * 60 + 121) * 1000;

        // 方式一:时间戳转化为日期类型
        Date date = new Date(current_date);
        System.out.println(date);

        // 方式二:将Date对象设置为表示 1970 年 1 月 1 日 00:00:00 GMT 之后的时间毫秒的时间点
        Date date1 = new Date();
        date1.setTime(current_date);
        System.out.println(date1);

    }
}

总结:

  1. 日期对象如何创建,如何获取时间毫秒值?

    • Date date = new Date();
    • Long time = date.getTime();
  2. 时间毫秒值怎么恢复成日期对象?

    Date date = new Date(time);
    date.setTime(time);
    
b.SimpleDateFormat

SimpleDateFormat类的作用:

  • 可以对Date对象或时间毫秒值格式化成我们喜欢的时间形式。

  • 也可以把字符串的时间形式解析成日期对象。

    // 格式化
    // Date对象 ——》 2022年6月16日 17:00
    // 时间毫秒值 ——》 2022年6月16日 17:00

    // 解析
    // 2022年6月16日 17:00 ——》 Date对象

SimpleDateFormat的构造器:

构造器

说明

public SimpleDateFormat()

构造一个SimpleDateFormat,使用默认格式。

public SimpleDateFormats(String pattern)

构造一个SimpleDateFormat,使用指定的格式

SimpleDateFormat的格式化方法:

格式化方法

说明

public final String format(Date date)

将日期格式化成日期/时间字符串。

public final String format(Object time)

将时间毫秒值式化成日期/时间字符串。

格式化的时间形式的常用的模块对应关系如下:

2022-06-16 18:00:00 -> yyyy-MM-dd HH:mm:ss

2022年06月16日 18:00:00 -> yyyy年MM月dd日 HH:mm:ss

  • y:年
  • M:月
  • d:日
  • H:时
  • m:分
  • s:秒

Test.java

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
    public static void main(String[] args) {
        // 日期对象
        Date date = new Date();
        System.out.println(date);

        // 创建格式化日期对象
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
        // 格式化日期对象
        String rs = simpleDateFormat.format(date);
        System.out.println(rs);

        // 格式化时间毫秒值
        // 求121之后的时间
        long time = System.currentTimeMillis() + 121 * 1000;
        String rs1 = simpleDateFormat.format(time);
        System.out.println(rs1);

    }
}

SimpleDateFormat解析字符串时间成为日期对象:

解析方法

说明

public Date parse(String source)

从给定字符串的开始解析文本以生成日期。

案例:请计算出2022年06月16日19点10分10秒,往后走3天20小时50分30秒后的时间是多少。

Test.java

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test1 {
    public static void main(String[] args) throws ParseException {
        // 解析字符串时间
        // 案例:请计算出2022年06月16日19点10分10秒,往后走3天20小时50分30秒后的时间是多少
        String dateStr = "2022年06月16日 19:10:10";

        // 字符串时间解析成日期对象
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        Date date = simpleDateFormat.parse(dateStr);

        // 往后走3天20小时50分30秒
        long time = date.getTime() + (3L * 24 * 60 * 60 + 20 * 60 * 60 + 50 * 60 + 30) * 1000;
        // 2022年06月20日 16:00:40
        System.out.println(simpleDateFormat.format(time));
    }
}

总结:

  1. SimpleDateFormat可以格式化哪些时间形式?

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    String rs1 = simpleDateFormat.format(date);
    String rs2 = simpleDateFormat.format(time);
    
  2. SimpleDateFormat如何进行字符串时间的解析?

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    Date date = simpleDateFormat.parse("2022-06-16 19:10:10")
    
案例:秒杀活动

需求:秒杀活动2022年6月18日 00:00:00 - 2022年6月18日 00:01:00

  • 小甲下单并付款的时间为:2022年6月18日 00:00:01
  • 小乙下单并付款的时间为:2022年6月18日 00:01:20
  • 用代码说明这两位同学有没有参加秒杀活动成功。

分析:

  • 判断下单时间是否在开始到结束的范围内。
  • 把字符串形式的时间变成毫秒值。

Test.java

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws ParseException {
        // 需求:秒杀活动2022年6月18日 00:00:00 - 2022年6月18日 00:01:00
        //
        //- 小甲下单并付款的时间为:2022年6月18日 00:00:01
        //- 小乙下单并付款的时间为:2022年6月18日 00:01:20
        //- 用代码说明这两位同学有没有参加秒杀活动成功。

        // 创建SimpleDateFormat对象
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

        // 活动开始时间
        String startTime = "2022年6月18日 00:00:00";
        // 活动结束时间
        String endTime = "2022年6月18日 00:01:00";
        // 小甲参加活动时间
        String JiaJoinTime = "2022年6月18日 00:00:01";
        // 小乙参加活动时间
        String YiJoinTime = "2022年6月18日 00:01:20";

        // 转成Date对象
        Date startTimestamp = simpleDateFormat.parse(startTime);
        Date endTimeTimestamp = simpleDateFormat.parse(endTime);
        Date JiaJoinTimestamp = simpleDateFormat.parse(JiaJoinTime);
        Date YiJoinTimestamp = simpleDateFormat.parse(YiJoinTime);

        if (whetherSucceed(startTimestamp, endTimeTimestamp, JiaJoinTimestamp)) {
            System.out.println("小甲参加活动成功!");
        } else {
            System.out.println("小甲参加活动失败!");
        }

        if (whetherSucceed(startTimestamp, endTimeTimestamp, YiJoinTimestamp)) {
            System.out.println("小乙参加活动成功!");
        } else {
            System.out.println("小乙参加活动失败!");
        }

    }

    /**
     * 判断是否参加活动成功
     *
     * @param startTime 活动开始时间
     * @param endTime 活动结束时间
     * @param joinTime 参加活动时间
     * @return 是否参加活动成功
     */
    public static boolean whetherSucceed(Date startTime, Date endTime, Date joinTime) {
        return joinTime.after(startTime) && joinTime.before(endTime);
    }
}
c.Calendar

Calendar概述:

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

Calendar日历类创建日历对象的方法:

方法名

说明

public static Calendar getInstance()

获取当前日历对象。

Calendar常用方法:

方法名

说明

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是可变日期对象,一旦修改后其对象本身表示的时间将产生变化。

Test.java

import java.util.Calendar;
import java.util.Date;

public class Test {
    public static void main(String[] args) {
        // | 方法名                                 | 说明                          |
        // | 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 = Calendar.getInstance();
        System.out.println(calendar);

        /* 获取日期中的某个字段信息 */
        int year = calendar.get(Calendar.YEAR);
        System.out.println(year + "年");

        // 月份从0开始计算
        int month = calendar.get(Calendar.MONTH) + 1;
        System.out.println(month + "月");

        int day = calendar.get(Calendar.DATE);
        System.out.println(day + "日");

        // 今天是一年中的第几天
        int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
        System.out.println("第" + dayOfYear + "天");

        /* 修改日历的某个字段信息 */
        // 修改当前日历对象的时间
        calendar.set(Calendar.HOUR, 19);
        System.out.println(calendar.get(Calendar.HOUR));

        /* 为某个字段增加/减少指定的值 */
        // 64天后的日期
        calendar.add(Calendar.DAY_OF_YEAR, 64);

        /* 拿到此刻日期对象 */
        Date date = calendar.getTime();
        System.out.println(date);

        /* 拿到此刻时间毫秒值 */
        long time = calendar.getTimeInMillis();
        System.out.println(time);
    }
}

总结:

  1. Calendar如何去得到日历对象的?

    // 获取当前日历对象
    public static Calendar getInstance()
    

2.JDK8新增日期类

a.概述、LocalTme/LocalDate/LocalDateTime
Ⅰ.概述
  • 从Java8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:
    • LocalDate:不包含具体时间和日期。
    • LocalTime:不包含日期的时间。
    • LocalDateTime:包含了日期及时间。
    • Instant:代表的是时间戳。
    • DateTimeFormatter:用于做时间的格式化和解析。
    • Duration:用于计算两个“时间”间隔。
    • Period:用于计算两个“日期”间隔。
  • 新增的API严格区分了时刻、本地日期、本地时间,并且对日期和时间进行运算更加方便。
  • 新增的API几乎全部是不变类型(和String的使用类似),可以放心使用不必担心被修改。
Ⅱ.LocalTime、LocalDate、LocalDateTime

LocalTime、LocalDate、LocalDateTime:

  • 分别表示时间对象、日期对象、时间日期对象,它们的类的实例是不可变的对象。
  • 它们三者构建对象和API都是通用的。

构建对象的方式如下:

方法名

说明

构建对象

public static xxx now();

静态方法,根据当前时间创建对象。

LocalDate localDate = LocalDate.now();
LocalTime localTime = LocatTime.now();
LocalDateTime localDateTime = LocalDateTime.now();

public static xxx of(…);

静态方法,,指定日期或时间创建对象

LocalDate localDate = LocalDate.of(2022, 06, 23);
LocalTime localTime = LocalTime.of(16:59:59);
LocalDateTime localDateTime = LocalDateTime.of(2022, 06, 23, 16, 59, 59);

获取信息的API:

方法名

说明

public int getYear()

获取年份。

public int getMonthValue()

获取月份(1-12)。

public int getDayOfMonth()

获取月中第几天。

public int getDayOfYear()0

获取年中第几天。

public DayOfWeek getDayOfWeek()

获取星期。

转换相关的API:

#mermaid-svg-Uhtx6fpEFdjcNCU2 {font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .error-icon{fill:#552222;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .marker.cross{stroke:#333333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 svg{font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .label{font-family:“trebuchet ms”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .cluster-label text{fill:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .cluster-label span{color:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .label text,#mermaid-svg-Uhtx6fpEFdjcNCU2 span{fill:#333;color:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .node rect,#mermaid-svg-Uhtx6fpEFdjcNCU2 .node circle,#mermaid-svg-Uhtx6fpEFdjcNCU2 .node ellipse,#mermaid-svg-Uhtx6fpEFdjcNCU2 .node polygon,#mermaid-svg-Uhtx6fpEFdjcNCU2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .node .label{text-align:center;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .node.clickable{cursor:pointer;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .arrowheadPath{fill:#333333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .cluster text{fill:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 .cluster span{color:#333;}#mermaid-svg-Uhtx6fpEFdjcNCU2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:“trebuchet ms”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Uhtx6fpEFdjcNCU2 :root{–mermaid-font-family:“trebuchet ms”,verdana,arial,sans-serif;}

LocalDateTime

LocalDate

LocalTime

方法名

说明

public LocalDate toLocalDate()

转换成一个LocalDate对象。

public LocalDate toLocalTime()

转换成一个LocalTime对象。

LocalDateDemo.java

import java.time.LocalDate;
import java.time.Month;

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

        // 获取本地日期实例
        LocalDate localDate = LocalDate.now();
        System.out.println("今天是:" + localDate);

        // 查看本地日期年份
        int year = localDate.getYear();
        System.out.println("今年是:" + year + "年");

        // 查看本地日期月份
        int month = localDate.getMonthValue();
        // 6
        System.out.println("本月是:" + month + "月");

        // 查看本地日期月份
        Month month1 = localDate.getMonth();
        // JUNE
        System.out.println(month1);
        // 6
        System.out.println(month1.getValue());

        // 查看本地日期本月日期
        int day = localDate.getDayOfMonth();
        System.out.println("今天是本月" + day + "日");

        // 查看本地日期今天是今年的第几天
        int dayOfYear = localDate.getDayOfYear();
        System.out.println("今天是今年的第" + dayOfYear + "天");

        // 查看本地日期今天星期几
        System.out.println(localDate.getDayOfWeek());
        System.out.println(localDate.getDayOfWeek().getValue());

        // 获取指定日期实例
        LocalDate localDate1 = LocalDate.of(2008, 8, 8);
        System.out.println(localDate1);
    }
}

LocalTimeDemo.java

import java.time.LocalTime;

public class LocalTimeDemo {
    public static void main(String[] args) {
        // 获取本地时间实例
        LocalTime localTime = LocalTime.now();
        System.out.println("本地时间是:" + localTime);

        // 获取本地时间的时钟
        int hour = localTime.getHour();
        System.out.println(hour);

        // 获取本地时间的分钟
        int minute = localTime.getMinute();
        System.out.println(minute);

        // 获取本地时间的秒钟
        int second = localTime.getSecond();
        System.out.println(second);

        // 获取本地时间的纳秒
        int nano = localTime.getNano();
        System.out.println(nano);

        // 指定时间实例
        System.out.println(LocalTime.of(9, 10));
        System.out.println(LocalTime.of(9, 10, 59));
        System.out.println(LocalTime.of(9, 10, 59, 999999999));

        // 获取指定时间实例
        LocalTime localTime1 = LocalTime.of(9, 10, 59, 999999999);
        System.out.println(localTime1.getHour());
        System.out.println(localTime1.getMinute());
        System.out.println(localTime1.getSecond());
        System.out.println(localTime1.getNano());
    }
}

LocalDateTimeDemo.java

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class LocalDateTimeDemo {
    public static void main(String[] args) {
        // 获取本地时间实例
        LocalDateTime localDateTime = LocalDateTime.now();

        System.out.println("今天是:" + localDateTime);
        System.out.println("今年是:" + localDateTime.getYear() + "年");
        System.out.println("本月是:" + localDateTime.getMonthValue() + "");
        System.out.println("今天是本月" + localDateTime.getDayOfMonth() + "日");

        // 时分秒
        System.out.println(
                "现在是北京时间"
                        + localDateTime.getHour() + "点"
                        + localDateTime.getMinute() + "分"
                        + localDateTime.getSecond() + "秒"
        );

        // 星期
        System.out.println(localDateTime.getDayOfWeek());
        System.out.println(localDateTime.getDayOfWeek().getValue());

        // 月份
        System.out.println(localDateTime.getMonth());
        System.out.println(localDateTime.getMonth().getValue());

        // 转化成LocalDate对象
        LocalDate localDate = localDateTime.toLocalDate();
        System.out.println(localDate);
        // 转成LocalTime对象
        LocalTime localTime = localDateTime.toLocalTime();
        System.out.println(localTime);

    }
}

修改相关的API:

  • LocalDateTime综合了LocalDate和LocalTime里面的方法,所以下面只用LocalDate和LocalTime来举例。
  • 这些方法返回的是一个新的实例引用,因为LocalDateTime、LocalDate、LocalTime都是不可变的。

方法名

说明

plusDay, plusWeeks, plusMonths, plusYears

向当前LocalDate对象添加几天、几周、几个月、几年。

minusDays, minusWeeks, minusMonths, minusYears

从当前LocalDate对象减去几天、几周、几个月、几年。

withDayOfMonth, withDayOfYear, withMonth, withYear

将月份天数、年份天数、月份、年份修改为指定的值并返回新的LocalDate对象。

isBefore, isAfter

比较两个LocalDate。

UpdateTimeDemo.java

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.MonthDay;

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

        // 方法名说明
        // plusDay, plusWeeks, plusMonths, plusYears向当前LocalDate对象添加几天、几周、几个月、几年。
        // minusDays, minusWeeks, minusMonths, minusYears从当前LocalDate对象减去几天、几周、几个月、几年。
        // withDayOfMonth, withDayOfYear, withMonth, withYear将月份天数、年份天数、月份、年份修改为指定的值并返回新的LocalDate对象。
        // isBefore, isAfter比较两个LocalDate。

        LocalTime localTime = LocalTime.now();
        System.out.println(localTime);

        // minusDays, minusWeeks, minusMonths, minusYears从当前LocalDate对象减去几天、几周、几个月、几年
        // 一小时前
        System.out.println(localTime.minusHours(1));
        // 一分钟前
        System.out.println(localTime.minusMinutes(1));
        // 一秒后
        System.out.println(localTime.minusSeconds(1));

        // plusDay, plusWeeks, plusMonths, plusYears向当前LocalDate对象添加几天、几周、几个月、几年。
        // 一小时后
        System.out.println(localTime.plusHours(1));
        // 一分钟后
        System.out.println(localTime.plusMinutes(1));
        // 一秒钟后
        System.out.println(localTime.plusSeconds(1));
        // 一纳秒后
        System.out.println(localTime.plusNanos(1));

        // 不可变对象 每次修改产生新对象
        System.out.println(localTime);

        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = LocalDate.of(2023, 1, 1);

        // 两个日期是否相等
        System.out.println(localDate.equals(localDate1));
        // 当前日期是否在指定日期之前
        System.out.println(localDate.isBefore(localDate1));
        // 当前日期是否在指定日期之后
        System.out.println(localDate.isAfter(localDate1));

        // 判断今天是否是你的生日
        LocalDate birthday = LocalDate.of(2000, 1, 1);

        // 月日对象
        // MonthDay birthMonth = MonthDay.of(birthday.getMonthValue(), birthday.getDayOfYear());
        MonthDay birthMonth = MonthDay.from(birthday);
        MonthDay nowMonth = MonthDay.from(localDate);
        System.out.println("今天是你的生日吗?" + birthMonth.equals(nowMonth));

    }
}
b.Instant

Instant时间戳:

  • JDK8获取时间戳特别简单,且功能更丰富。Instant类由一个静态的工厂方法now()可以返回当前时间戳。

    Instant instant = Instant.now();
    System.out.println("当前时间戳是:" + instant)
    
    // Instant对象转为Date对象
    Date date = Date.from(instant);
    System.out.println("当前时间戳是:" + date);
    
    // Date对象转为Instant对象
    instant = date.toInstant();
    System.out.println(instant);
    
  • 时间戳是包含日期和时间的,与java.util.Date很类似,事实上Instant就是类似JDK8以前的Date。

  • Instant和Date这两个类可以进行转换。

InstantDemo.java

import java.time.Instant;
import java.time.ZoneId;
import java.util.Date;

public class InstantDemo {
    public static void main(String[] args) {
        // 获取时间戳对象
        // 格林威治时间/世界时
        Instant instant = Instant.now();
        System.out.println(instant);

        // 本地时间戳
        System.out.println(instant.atZone(ZoneId.systemDefault()));

        // Instant对象转为Date对象
        Date date = Date.from(instant);
        System.out.println(date);
        
        // Date对象转为Instant对象
        instant = date.toInstant();
        System.out.println(instant);
    }
}
c.DateTimeFormatter

DateTimeFormatter 日期时间格式化:

  • 在JDK8中,引入了一个全新的日期与时间格式器DateTimeFormatter。

  • 正反都能调用format方法。

    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime);

    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);

    String localDateTimeString = localDateTime.format(dateTimeFormatter);
    System.out.println(localDateTimeString);

    String localDateTimeString1 = dateTimeFormatter.format(localDateTime);
    System.out.println(localDateTimeString1);

DateTimeFormatterDemo.java

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class DateTimeFormatterDemo {
    public static void main(String[] args) {
        // 获取日期时间对象
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);

        // 获取日期时间格式化器对象
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EEE a");

        // 格式化日期时间对象 正向格式化
        String localDateTimeString = localDateTime.format(dateTimeFormatter);
        System.out.println(localDateTimeString);

        // 格式化日期时间对象 逆向格式化
        String localDateTimeString1 = dateTimeFormatter.format(localDateTime);
        System.out.println(localDateTimeString1);

        // 解析字符串时间
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String dateString = "2023-01-01 10:59:59";

        // 解析当前字符串日期时间成为本地日期时间对象
        LocalDateTime localDateTime1 = LocalDateTime.parse(dateString, dateTimeFormatter1);
        System.out.println(localDateTime1);

        System.out.println(localDateTime1.getYear());
        System.out.println(localDateTime1.getMonthValue());
        System.out.println(localDateTime1.getDayOfYear());

    }
}
d.Duration/Period
Ⅰ.Period
  • 在Java8中,我们可以使用以下类来计算日期间隔差异:java.time.Period。

  • 主要是Period类方法getYears(),getMonths()和getDays()来计算,只能精确到年月日。

  • 用于LocalDate之间的比较。

    LocalDate localDate = LocalDate.now();
    System.out.println(localDate);

    LocalDate birthDate = LocalDate.of(2000, 1, 1);
    System.out.println(birthDate);

    Period period = Period.between(birthDate, localDate);
    System.out.printf(“年龄:%d年%d月%日”, period.getYears(), period.getMonths(), period.getDays());

PeriodDemo.java

import java.time.LocalDate;
import java.time.Period;

public class PeriodDemo {
    public static void main(String[] args) {
        // 获取本地日期对象
        LocalDate localDate = LocalDate.now();
        System.out.println(localDate);

        // 生日
        LocalDate birthday = LocalDate.of(2000, 1, 1);
        System.out.println(birthday);

        // 计算两个日期相差的 年月日
        Period period = Period.between(birthday, localDate);
        System.out.println(period.getYears());
        System.out.println(period.getMonths());
        System.out.println(period.getDays());
    }
}
Ⅱ.Duration
  • 在Java8中,我们可以使用以下类来计算时间间隔差异:java.time.Duration

  • 提供了使用基于时间的测量时间量的方法。

  • 用于LocalDateTime之间的比较。也可用于Instant之间的比较。

    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime);

    LocalDateTime birthDate = LocalDateTime.of(2000, 1, 1, 10, 59, 59);
    System.out.println(birthDate);

    Duration duration = Duration.between(today, birthDate);
    // 计算两个时间差的天数
    System.out.println(duration.toDays());
    // 计算两个时间戳的小时数
    System.out.println(duration.toHours());
    // 计算两个时间差的分钟数
    System.out.println(duration.toMinutes());
    // 计算两个时间差的毫秒数
    System.out.println(duration.toMillis());
    // 计算两个时间差的纳秒数
    System.out.println(duration.toNanos());

Ⅲ.总结
  1. Duration:用于计算两个“时间”间隔。
  2. Period:用于计算两个“日期”间隔。
e.ChronoUnit

ChronoUnit:

  • ChronoUnit类可用于在单个时间单位内测量一段时间,这个工具类是最全的了,可以用于比较所有的时间单位。

    LocalDateTime localDateTime = LocalDateTime.now();
    System.out.println(localDateTime);
    
    LocalDateTime birthday = LocalDateTime.of(2000, 1, 1, 10, 59, 59);
    System.out.println(birthday)
    
    System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthday, localDateTime));
    System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthday, localDateTime));
    System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthday, localDateTime));
    System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthday, localDateTime));
    System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthday, localDateTime));
    System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthday, localDateTime));
    System.out.println("相差的秒数:" + ChronoUnit.SECONDS.between(birthday, localDateTime));
    System.out.println("相差的毫秒数:" + ChronoUnit.MILLIS.between(birthday, localDateTime));
    System.out.println("相差的微秒数:" + ChronoUnit.MICROS.between(birthday, localDateTime));
    System.out.println("相差的纳秒数:" + ChronoUnit.NANOS.between(birthday, localDateTime));
    System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthday, localDateTime));
    System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthday, localDateTime));
    System.out.println("相差的世纪(百年)数:" + ChronoUnit.CENTURIES.between(birthday, localDateTime));
    System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthday, localDateTime));
    System.out.println("相差的纪元数:" + ChronoUnit.ERAS.between(birthday, localDateTime));
    

3.包装类

包装类:

  • 其实就是8中基本类型对应的引用类型。

    基本数据类型

    引用数据类型

    byte

    Byte

    short

    Short

    int

    Integer

    long

    Long

    char

    Character

    float

    Float

    double

    Double

    boolean

    Boolean

为什么提供包装类?

  • Java为了实现一切皆对象,为8中基本类型提供了对应的引用类型。
  • 后面的集合和泛型其实也只能支持包装类型,不支持基本数据类型。

自动装箱:

  • 基本类型的数据和变量可以直接赋值给包装类型的变量。

自动拆箱:

  • 包装类型的变量可以直接赋值给基本数据类型的变量。

包装类的特有功能:

  • 包装类的变量的默认值可以是null,容错率更高。
  • 可以把基本数据的数据转换成字符串类型(用处不大)。
    1. 调用toString()方法得到字符串结果。
    2. 调用Integer.toString(基本类型的数据)。
  • 可以把字符串类型的数值转换成真实的数据类型(很有用)。
    1. Integer.parseInt(“字符串类型的整数”)。
    2. Double.parseDouble(“字符串类型的小数”)。

Test.java

/**
 * 目标:理解包装类的概念,并使用。
 */
public class Test {
    public static void main(String[] args) {

        int a = 10;
        Integer b = 11;

        System.out.println(a);
        System.out.println(b);

        // 自动装箱
        Integer a1 = a;
        // 自动拆箱
        int b1 = b;

        System.out.println(a1);
        System.out.println(b1);

        // 包装类容错率更高
        Integer temp = null;
        Integer temp1 = 0;

        System.out.println(temp);
        System.out.println(temp1);

        // 基本类型的数据转换成字符串类型
        Integer i = a;
        System.out.println(i.toString() + "示例");

        // 字符串类型的数值转换成真实的数据类型
        System.out.println(Integer.parseInt("123") + 1000);
        System.out.println(Integer.valueOf("123") + 1000);
        System.out.println(Double.parseDouble("123.9") + 1000.0);
        System.out.println(Double.valueOf("123.9") + 1000.0);

    }
}

总结:

  1. 包装类是什么,目的是什么?
    • 基本数据类型对应的引用类型。
    • 实现了一切皆对象。
    • 后期集合和泛型不支持基本类型,只能使用包装类。
  2. 包装类有哪些特殊功能?
    • 可以把基本类型的数据转换成字符串类型(用处不大)。
    • 可以把字符串类型的数值转换成真实的数据类型(很有用)。

4.正则表达式

a.正则表达式概述

正则表达式:

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

正则表达式体验:

  • 需求:现在要求校验一个QQ号码是否正确,QQ号码为6位至20位以内的数字。
  • 先使用目前所学知识完成校验需求,然后再用正则表达式完成校验需求。

Test.java

public class Test {
    public static void main(String[] args) {
        // 需求:校验QQ号码 6至20位数字
        System.out.println(checkQQ("1501960853"));
        System.out.println(checkQQ("A501960853"));

        // 正则表达式校验
        System.out.println(checkQQRegex("1501960853"));
        System.out.println(checkQQRegex("A501960853"));

    }
    public static boolean checkQQRegex(String qq) {
        return qq != null && qq.matches("\d{6,20}");
    }

    public static boolean checkQQ(String qq) {

        // 过滤非正常情况
        if (qq == null || qq.length() < 6 || qq.length() > 20) {
            return false;
        }

        // 判断QQ号码是否全部为数字
        for (int i = 0; i < qq.length(); i++) {
            // 获取每位字符
            char ch = qq.charAt(i);

            // 判断是否为数字
            if (ch < '0' || ch > '9') {
                return false;
            }
        }

         return true;
    }
}
b.正则表达式匹配规则

字符类(默认匹配一个字符):

[abc] 只能是a, b, 或c
[^abc] 除了a, b, c之外的任何字符
[a-zA-Z] a到z和A到Z
[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]减法)

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

. 任何字符
d 一个数字:[0-9]
D 非数字:[^0-9]
s 一个空白字符:[	

]
S 非空白字符:[^s]
w [a-zA-Z_0-9]英文、数字、下划线
W [^w]一个非单词字符

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

X? X, 一次或根本不
X* X, 零次或多次
X+ X,一次或多次
X{n} X, 正好n次
X{n, } X,至少n次
X{n, m} X, 至少n但不超过m次

字符串对象提供了匹配正则表达式规则的API:

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

Test.java

public class Test {
    public static void main(String[] args) {
        System.out.println("a".matches("[abc]"));
        System.out.println("z".matches("[abc]"));

        // 校验密码 必须是数字、字母、下划线 至少6位
        System.out.println("abc123efg_".matches("\w{6,}"));

        // 验证码 必须是数字和字符 必须是4位
        System.out.println("12ab".matches("[a-zA-Z0-9]{4}"));
        System.out.println("12ab".matches("[a-zA-Z\d]{4}"));
        System.out.println("12ab".matches("\w&&[^_]{4}"));
    }
}

总结:

  1. String类的哪个方法可以与正则表达式进行匹配。

    public boolean matches(String regex) {}
    
c.正则表达式的常见案例

案例:请使用正则表达式完成如下需求

需求:

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

分析:

  • 定义方法,接收用户输入的数据,使用正则表达式完成检验,并给出提示。

Test.java

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        // - 请编写程序模拟用户输入手机号码格式正确,并给出提示,直到格式输入正确为止。
        checkPhone();

        // - 请编写程序模拟用户输入邮箱号码格式正确,并给出提示,直到格式输入正确为止。
        checkEmail();

        // - 请编写程序模拟用户输入电话号码格式正确,并给出提示,直到格式输入正确为止。
        checkTelephoneNumber();
    }

    /**
     * 检查电话号码格式
     * 010-8888888
     * 0108888888
     */
    private static void checkTelephoneNumber() {

        // 创建扫描器对象
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("请您输入您的注册邮箱:");
            String telephoneNumber = scanner.next();

            // 判断手机号码格式是否正确
            if (telephoneNumber.matches("0\d{2,6}-?\d{5,20}")) {
                System.out.println("电话号码格式正确,注册成功!");
                break;
            } else {
                System.out.println("电话号码格式错误,注册失败!");
            }
        }
    }

    /**
     * 检查邮箱格式
     *
     * [email protected]
     * [email protected]
     * [email protected]
     */
    private static void checkEmail() {

        // 创建扫描器对象
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("请您输入您的注册邮箱:");
            String email = scanner.next();

            // 判断手机号码格式是否正确
            if (email.matches("\w{1,30}@[a-zA-Z\d]{2,20}(\.[a-zA-Z\d]{2,20}){1,2}")) {
                System.out.println("邮箱格式正确,注册成功!");
                break;
            } else {
                System.out.println("邮箱格式错误,注册失败!");
            }
        }
    }

    /**
     * 检查手机号码格式
     */
    public static void checkPhone() {

        // 创建扫描器对象
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("请您输入您的注册手机号码:");
            String phoneNumber = scanner.next();

            // 判断手机号码格式是否正确
            if (phoneNumber.matches("1[3-9]\d{9}")) {
                System.out.println("手机号码格式正确,注册成功!");
                break;
            } else {
                System.out.println("手机号码格式错误,注册失败!");
            }
        }

    }
}
d.正则表达式在方法中的应用

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

方法名

说明

public String replaceAll(String regex, String newStr)

按照正则表达式匹配的内容进行替换。

public String[] split(String regex)

按照正则表达式匹配的内容进行分割字符串,返回一个字符串数组。

Test.java

public class Test {
    public static void main(String[] args) {
        String names = "白子画abcdefg花千骨xxxsadfs杀阡陌xsdfas琉夏";

        // 按照一段一段连续[英文、数字、下划线]来分割
        String[] nameArray = names.split("\w+");

        for (String s : nameArray) {
            System.out.println(s);
        }

        // 将一段一段[英文、数字、下划线]替换成一个空格
        String names2 = names.replaceAll("\w+", " ");
        System.out.println(names2);
    }
}
e.正则表达式爬取信息

Test.java

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串中提取手机号码和邮箱
 */
public class Test {
    public static void main(String[] args) {
        String s = "学修仙到长留山学院,电话010-88888888, 电话010888888888, 邮箱:[email protected], 或拨打电话400-010-8888";


        // 定义爬去规则
        String regex = "(\w{1,30}@[a-zA-Z\d]{2,20}(\.[a-zA-Z\d]{2,20}){1,2})" +
                "|(1[3-9]\d{9}|0\d{2,6}-?\d{5,20})" +
                "|(400-?\d{3,9}-?\d{3,9})";

        // 爬去规则编译成匹配对象
        Pattern pattern = Pattern.compile(regex);

        // 得到一个内容匹配器对象
        Matcher matcher = pattern.matcher(s);

        // 开始爬取数据
        while (matcher.find()) {
            String rs = matcher.group();
            System.out.println(rs);
        }
    }
}

5.Arrays类

a.Arrays类概述、常用功能演示

Arryas类概述:

  • 数组操作工具类,专门用于操作数组元素。

Arrays类的常用API:

方法名

说明

public static String toString(类型[] a)

返回指定数组内容的字符串表示形式。

public static void sort(类型[] a)

对数组进行默认升序排序。

public static void sort(类型[] a, Comparator c)

使用比较器对象自定义排序。

public static int binarySearch(int[] a, int key)

二分搜索数组中的数据,存在返回索引,不存在返回 -(应当插入的位置索引 + 1)。

Test.java

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        // 目标:学会使用Arrays类常用API
        int[] array = {22, 11, 66, 33, 44, 55};
        System.out.println(array);

        // 返回指定数组内容的字符串表示形式
        String s = Arrays.toString(array);
        System.out.println(s);

        // 对数组进行默认升序排序
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));

        // 二分搜索技术(前提数组必须排好序, 否则抛出异常) 存在返回索引,不存在返回 -(应当插入的位置索引 + 1)
        int index = Arrays.binarySearch(array, 33);
        System.out.println(index);
        int index1 = Arrays.binarySearch(array, 99);
        System.out.println(index1);

        // 二分搜索 未排序情况可能会找不到存在的元素
        int[] array2 = {22, 11, 66, 33, 44, 55};
        System.out.println(Arrays.binarySearch(array2, 11));
        System.out.println(Arrays.binarySearch(array2, 33));

    }
}

二分查找源码:

    private static int binarySearch0(int[] a, int fromIndex, int toIndex, int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while(low <= high) {
            int mid = low + high >>> 1;
            int midVal = a[mid];
            if (midVal < key) {
                low = mid + 1;
            } else {
                if (midVal <= key) {
                    return mid;
                }

                high = mid - 1;
            }
        }

        return -(low + 1);
    }
b.Arrrays类对于Comparator比较器的支持

Arrays类的排序方法:

方法名

说明

public static void sort(类型[] a)

对数组进行默认升序排序。

public static void sort(类型[] a, Comparator< super T> c)

使用比较器对象自定义排序。

自定义排序规则:

  • 设置Comparator接口对应的比较器对象,来定制比较规则。
  • 如果认为左边数据大于右边数据返回正整数。
  • 如果认为左边数据小于右边数据返回负整数。
  • 如果认为左边数据等于右边数据返回0。

Student.java

public class Student {
    private String name;
    private int age;
    private double height;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public Student() {
    }

    public Student(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

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

Test.java

import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        // 目标:自定义数组的排序规则:Comparator比较器对象
        // Arrays的sort方法对于默认值特性的数组是升序排序
        int[] ages = {21, 23, 38, 18, 16};
        Arrays.sort(ages);
        System.out.println(Arrays.toString(ages));

        // 降序排序(自定义比较器对象, 只能支持引用类型的排序)
        Integer[] ages1 = {22, 23, 38, 18, 16};
        // 参数一:被排序的数组 必须是引用类型的元素
        // 参数二:匿名内部类 代表了一个比较器对象
        Arrays.sort(ages1, new Comparator<Integer>() {
            @Override
            public int compare(Integer integer, Integer integer1) {

                // 制定比较规则 升序排序
//                if (integer > integer1) {
//                    return 1;
//                } else if (integer < integer1) {
//                    return -1;
//                }
//                return 0;
                // 返回正整数 升序排序
//                return integer - integer1;
                // 返回负整数 降序排序
                return integer1 - integer;
            }
        });
        System.out.println(Arrays.toString(ages1));

        System.out.println("---------------------------------");
        // 创建学生对象数组
        Student[] students = new Student[3];
        students[0] = new Student("白子画", 1000, 180);
        students[1] = new Student("花千骨", 16, 165);
        students[2] = new Student("轻水", 18, 170);

        System.out.println(Arrays.toString(students));

        // 学生排序
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student student, Student student1) {
                // 自己制定比较规则
                // 按照年龄升序排序
                // return student.getAge() - student1.getAge();
                // return student1.getAge() - student.getAge();

                // 按照身高升序排序
                // Double.compare() 比较浮点型数据 返回 -1, 0, 1
                // return Double.compare(student.getHeight(), student1.getHeight());
                // 按照身高降序排序
                return Double.compare(student1.getHeight(), student.getHeight());
            }
        });
    }
}

6.常见算法

Ⅰ.选择排序

选择排序的思想:

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

在这里插入图片描述

选择排序的关键:

  • 确定总共需要选择几轮:数组的长度-1。
  • 控制每轮从以前位置为基准,与后面元素选择几次。

Test.java

import java.util.Arrays;

/**
 * 选择排序
 */
public class Test {
    public static void main(String[] args) {
        // 创建数组
        int[] array = {5, 1, 3, 2};

        // 定义一个循环控制选择几轮
        for (int i = 0; i < array.length  - 1; i++) {

            // 定义内部循环 控制选择几次
            for (int j = i + 1; j < array.length; j++) {

                if (array[i] > array[j]) {
                    // 如果当前位置比后一个位置的值小, 相互交换值
                    int temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(array));
    }
}
Ⅱ.二分查找

基本查找:从前往后寻找,数据量大时查询性能很差。

二分查找:查询性能好,二分查找的前提是必须是排好序的数据。

在这里插入图片描述

Test.java

public class Test {
    public static void main(String[] args) {
        // 创建数组
        int[] array = {1, 3, 4, 6, 7, 8, 10, 13, 14};

        // 1
        System.out.println(binarySearch(array, 3));
        // 6
        System.out.println(binarySearch(array, 10));
        // -1
        System.out.println(binarySearch(array, 22));

    }

    /**
     * 二分查找
     *
     * @param array 升序数组
     * @param i 目标数据
     * @return 目标数据的索引或元素不存在返回-1
     */
    public static int binarySearch(int[] array, int i) {

        // 最左边位置索引
        int left = 0;
        // 最右边位置索引
        int right = array.length - 1;

        // 开始循环 折半查询
        while (left <= right) {
            // 取中间索引
            int mid = (left + right) / 2;

            // 判断当前中间位置的数据和目标数据的大小情况
            if (i > array[mid]) {
                // 往右寻找 最左索引更新
                left = mid + 1;
            } else if (i < array[mid]) {
                // 往左寻找 最右索引更新
                right = mid - 1;
            } else if (i == array[mid]) {
                return mid;
            }
        }

        // 元素不存在返回
        return -1;
    }
}

总结:

  1. 数组的二分查找的实现步骤是什么样的?
    • 定义变量记录左边和右边位置。
    • 使用while循环控制查询(条件是左边位置>=右边位置)。
    • 循环内部获取中间元素索引。
    • 判断当前要找的元素如果大于中间元素,左边位置=中间索引+1。
    • 判断当前要找的元素如果小于中间元素,右边位置=中间索引-1。
    • 判断当前要找的元素如果等于中间元素,返回当前中间元素索引。

7.Lambda表达式枚举

a.Lambda概述

Lambda概述:

  • Lambda表达式是JDK8开始后的一种新语法形式。
  • 作用:简化匿名内部类的代码写法。

Lambda表达式的简化格式:

(匿名内部类被重写方法的形参列表) -> {
    被重写方法的方法体代码
}

// 注意: ->是语法形式,无实际含义
// 注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式

什么是函数式接口?

  • 首先必须是接口、其次接口中有且仅有一个抽象方法的形式。
  • 通常我们会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口。

Test.java

public class Test {
    public static void main(String[] args) {
        // 目标:学会使用Lambda的标准格式简化匿名内部类的代码形式
        // Lambda只能简化接口中只有一个抽象方法的匿名内部类形式
        System.out.println("--------------匿名内部类--------------");
        Swimming swimming = new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师游泳很厉害!");
            }
        };
        go(swimming);

        System.out.println("--------------Lambda简化匿名内部类--------------");
        Swimming swimming1 = () -> {
            System.out.println("学生游泳很厉害!");
        };
        go(swimming1);

        System.out.println("--------------Lambda进一步简化匿名内部类--------------");
        go(() -> {
            System.out.println("历史老师游泳很厉害!");
        });
    }

    public static void go(Swimming swimming) {
        System.out.println("开始游泳");
        swimming.swim();
        System.out.println("结束游泳");
    }
}

/**
 * 游泳接口
 *
 * 加上@FunctionalInterface之后 接口中里面只能有一个抽象方法
 */
@FunctionalInterface
interface Swimming {
    void swim();
}

总结:

  1. Lambda表达式的基本作用?
    • 简化函数式接口的匿名内部类的写法。
  2. Lambda表达式有什么使用前提?
    • 必须是接口的匿名内部类,接口中只能有一个抽象方法。
  3. Lambda的好处?
    • Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,它可以写出更简洁、更灵活的代码,作为一种更紧凑的代码风格,使Java语言表达能力得到了提升。
b.Lambda实战-简化常见函数式接口

Lambda表达式简化Comparator接口的匿名形式:

简化前:

public static void main(String[] args) {
    Integer[] ages = {33, 11, 22, 55, 44, 66};
    
    Arrays.sort(ages, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2- o1;
        }
    });
    
    System.out.println("内容:" + Arrays.toString(ages));
}

简化后:

public static void main(String[] args) {
    Integer[] ages = {33, 11, 22, 55, 44, 66};
    
    Arrays.sort(ages, (Integer o1, Integer o2) -> {
        return o2- o1;
    });
    
    System.out.println("内容:" + Arrays.toString(ages));
}

Lambda表达式简化按钮监听器ActionListener的匿名内部类形式:

简化前:

JButton btn = new JButton("登录");

btn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("登录成功");
    }
})

简化后:

JButton btn = new JButton("登录");

btn.addActionListener((ActionEvent e) -> {
    System.out.println("登录成功");
});

Test.java

import java.util.Arrays;

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

        Integer[] ages = {22, 23, 38, 18, 16};
        System.out.println(Arrays.toString(ages));

        // 降序排序
        Arrays.sort(ages, (Integer integer, Integer integer1) -> {
                    return integer1 - integer;
                }
        );

        System.out.println(Arrays.toString(ages));

        // 降序排序
        Arrays.sort(ages, (Integer integer, Integer integer1) -> integer1 - integer
        );
        System.out.println(Arrays.toString(ages));
    }
}
c.Lambda表达式的省略规则

Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化):

  • 参数类型可以省略不写。

  • 如果只有一个参数,参数类型可以省略,同时()也可以省略。

  • 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!

  • 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略分号不写。

    public static void main(String[] args) {
    Integer[] ages = {33, 11, 22, 55, 44, 66};

    Arrays.sort(ages, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2- o1;
        }
    });
    
    System.out.println("内容:" + Arrays.toString(ages));
    

    }

简化后:

public static void main(String[] args) {
    Integer[] ages = {33, 11, 22, 55, 44, 66};
    
    Arrays.sort(ages, (Integer o1, Integer o2) -> {
        return o2- o1;
    });
    
    System.out.println("内容:" + Arrays.toString(ages));
}

Lambda表达式简化按钮监听器ActionListener的匿名内部类形式:

简化前:

JButton btn = new JButton("登录");

btn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("登录成功");
    }
})

简化后:

JButton btn = new JButton("登录");

btn.addActionListener((ActionEvent e) -> {
    System.out.println("登录成功");
});

Test.java

import java.util.Arrays;

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

        Integer[] ages = {22, 23, 38, 18, 16};
        System.out.println(Arrays.toString(ages));

        // 降序排序
        Arrays.sort(ages, (Integer integer, Integer integer1) -> {
                    return integer1 - integer;
                }
        );

        System.out.println(Arrays.toString(ages));

        // 降序排序
        Arrays.sort(ages, (Integer integer, Integer integer1) -> integer1 - integer
        );
        System.out.println(Arrays.toString(ages));
    }
}
c.Lambda表达式的省略规则

Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化):

  • 参数类型可以省略不写。
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略。
  • 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!
  • 如果Lambda表达式的方法体代码只有一行代码,可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略分号不写。
;