写在前面:
每一个不曾起舞的日子,都是对生命的辜负。
希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己。
以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力有限,哪里写的不够清楚、明白,还请各位不吝指正,欢迎交流与讨论。如果有朋友因此了解了一些知识或对Java有了更深层次的理解,从而进行更进一步的学习,那么这篇文章的意义也就达到了。
目录
2.2LocalTime /LocalDate / LocalDateTime
常用API、Lambda、常见算法
1.日期与时间
1.1Date
Date类概述
Date类的对象在Java中代表当前所在系统的日期时间信息。
Date构造器
名称 | 说明 |
public Date() | 创建一个Date对象,代表的是系统当前时刻的日期时间信息 |
public Date(long time) | 把时间毫秒值转换成Date日期对象 |
Date的常用方法
名称 | 说明 |
public long getTime() | 返回从1970年1月1日 00:00:00走到此刻的总的毫秒数 |
public void setTime(long time) | 设置日期对象的时间为当前时间毫秒值对应的时间 |
示例代码如下:
// 创建一个类Date类的对象,代表系统此刻日期时间对象
Date d = new Date();
System.out.println(d);
// 获取时间毫秒值
long time = d.getTime();
System.out.println(time);
// System类中获取时间毫秒值的静态方法
// long time2 = System.currentTimeMillis();
// System.out.println(time2);
System.out.println("--------------");
// 案例:请计算出当前时间往后走1小时121秒之后的时间是多少
Date d1 = new Date();
System.out.println(d1);
// 1.获取当前时间对应的毫秒值
long time2 = System.currentTimeMillis();
time2 += (60 * 60 + 121) * 1000;
// 2.将更改后的时间毫秒值转换为日期对象
// 第一种方式:调用public Date(long time)构造器
// Date d2 = new Date(time2);
// System.out.println(d2);
// 第二种方式:调用public void setTime(long time)方法
d1.setTime(time2);
System.out.println(d1);
}
1.2SimpleDateFormat
SimpleDateFormat类作用
如下图所示,可以对Date对象或时间毫秒值格式化成我们喜欢的时间形式,也可以把字符串的时间形式解析成Date对象。
SimpleDateFormat的构造器
构造器 | 说明 |
public SimpleDateFormat() | 构造一个SimpleDateFormat,使用默认格式 |
public SimpleDateFormat(String pattern) | 构造一个SimpleDateFormat,使用指定格式 |
SimpleDateFormat的格式化方法
格式化方法 | 说明 |
public final String format(Date date) | 将日期格式化成日期/时间字符串 |
public final String format(Object time) | 将时间毫秒值格式化成日期/时间字符串 |
public Date parse(String source) | 从给定字符串的开始解析文本以生成日期 |
格式化的时间形式的常用的模式对应关系如下图所示。
示例代码如下:
public class SimpleDateFormatDemo1 {
public static void main(String[] args) {
// 1.获取日期对象
Date d = new Date();
System.out.println(d);
// 2.获取格式化日期对象(指定最终格式化的形式)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a"); // EEE代表取周几 a代表取上午/下午
// 3.将日期对象格式化为字符串形式
String rs = sdf.format(d); // 调用SimpleDateFormat对象中重载的format(Date date)方法,将日期转换为格式化后的日期字符串形式
System.out.println(rs);
System.out.println("----------");
// 格式化日期毫秒值为字符串形式
// 需求:100s后的时间是多少
long time = System.currentTimeMillis(); // 获取当前时间毫秒值
time += 100 * 1000; // 获取100s后的时间毫秒值
// 调用SimpleDateFormat对象中重载的format(Object time)方法,将时间毫秒值转换为格式化后的日期字符串形式
System.out.println(sdf.format(time));
}
}
public class SimpleDateFormatDemo2 {
public static void main(String[] args) throws ParseException {
System.out.println("------解析字符串时间------");
// 需求:请计算出 2021年08月06日11点11分11秒,往后走2天14小时49分06秒后的时间是多少
// 把字符串时间拿到程序中
String dateStr = "2021年08月06日 11点11分11秒";
// 把字符串时间解析为日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH点mm分ss秒"); // 格式必须与被解析的字符串时间形式一模一样,否则运行时解析会出现错误
Date d = sdf.parse(dateStr);
// 时间毫秒值向后走2天14小时49分06秒
long time = d.getTime() + (2L * 24 * 60 * 60 + 14 * 60 * 60 + 49 * 60 + 6) * 1000; // 默认是int型的计算,有可能会发生数据越界,因此在第一个数字后加L,使数据在进行运算时自动转换为long型
// 将时间毫秒值格式化为字符串时间
String dateStr2 = sdf.format(time);
System.out.println(dateStr2);
}
}
注:SimpleDateFormat解析字符串时间成为日期对象,在进行SimpleDateFormat构造器声明的时候,格式必须与被解析的字符串时间形式一模一样,否则运行时解析会出现错误。
练习:秒杀活动
需求:某购物网站举办秒杀活动,开始时间2020年11月11日 0:0:0、结束时间2020年11月11日 0:10:0,当前活动结束后,系统记录到2位用户的付款时间分别如下:
小贾下单并付款的时间为:2020年11月11日 0:03:47
小皮下单并付款的时间为:2020年11月11日 0:10:11
规则:顾客的付款时间必须在秒杀时间之内,请判断出两位顾客是否秒杀成功
分析:
把4个字符串形式的时间解析成日期对象。
判断小贾和小皮的时间是否在秒杀时间范围之内,并给出相应的提示。
示例代码如下:
public class SimpleDateFormatTest3 {
public static void main(String[] args) throws ParseException {
/**
需求:某购物网站举办秒杀活动,开始时间2020年11月11日 0:0:0、结束时间2020年11月11日 0:10:0,当前活动结束后,系统记录到2位用户的付款时间分别如下:
小贾下单并付款的时间为:2020年11月11日 0:03:47
小皮下单并付款的时间为:2020年11月11日 0:10:11
规则:顾客的付款时间必须在秒杀时间之内,请判断出两位顾客是否秒杀成功
*/
String startDateStr = "2020年11月11日 0:0:0"; // 秒杀开始时间
String endDateStr = "2020年11月11日 0:10:0"; // 秒杀结束时间
String jiaDateStr = "2020年11月11日 0:03:47"; // 小贾付款时间
String piDateStr = "2020年11月11日 0:10:11"; // 小皮付款时间时间
// 调用判断是否抢购成功的方法
isPaySuccess(startDateStr, endDateStr, jiaDateStr);
isPaySuccess(startDateStr, endDateStr, piDateStr);
}
// 判断是否抢购成功
public static void isPaySuccess(String startDateStr, String endDateStr, String payDateStr) throws ParseException {
// 把字符串时间解析为日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date startDate = sdf.parse(startDateStr);
Date endDate = sdf.parse(endDateStr);
Date payDate = sdf.parse(payDateStr);
// 判断付款时间是否在规定时间内,并给出相应提示
if (payDate.before(startDate)) {
System.out.println("未到抢购时间");
} else if ((payDate.after(startDate)) & (payDate.before(endDate))) {
System.out.println("抢购成功!");
} else {
System.out.println("抢购时间已过!");
}
}
}
1.3Calendar
Calendar概述
Calendar代表了系统此刻日期对应的日历对象。
Calendar是一个抽象类,不能直接创建对象。
Calendar常用方法
方法名 | 说明 |
public static Calendar getInstance() | 获取当前日历对象 |
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() | 拿到此刻时间毫秒值 |
示例代码如下:
public static void main(String[] args) {
// 1.public static Calendar getInstance() 获取当前日历对象
Calendar cal = Calendar.getInstance();
System.out.println(cal);
// 2.public int get(int field) 取日期中的某个字段信息
int year = cal.get(Calendar.YEAR);
System.out.println(year);
int month = cal.get(Calendar.MONTH) + 1; // 月份是从0开始计算,因此真实月份需要在日历中取出来的基础上 + 1
System.out.println(month);
int day = cal.get(Calendar.DATE);
System.out.println(day);
int days = cal.get(Calendar.DAY_OF_YEAR); // 一年中的第几天
System.out.println(days);
// 3.public void set(int field,int value) 修改日历的某个字段信息
// cal.set(Calendar.HOUR, 7); // 将日历中的时间修改为7点(12小时制,分上午/下午,如果输入12-24会顺延计算)
// System.out.println(cal.get(Calendar.HOUR));
// 4.public void add(int field,int amount) 为某个字段增加/减少指定的值
cal.add(Calendar.DATE, 5); // 将日历中的日期增加5天
System.out.println(cal.get(Calendar.DATE));
// 5.public final Date getTime() 拿到此刻日期对象
Date date = cal.getTime();
System.out.println(date); // 当前日期对象,Date类型 Date d = new Date(); long time = d.getTime(); 获取的是当前时刻对应的毫秒值,long类型
// 6.public long getTimeInMillis() 拿到此刻时间毫秒值
long time = cal.getTimeInMillis();
System.out.println(time);
}
}
注:Calendar是可变日期对象,一旦修改后其对象本身表示的时间将产生变化。
2.JDK8新增日期类
2.1概述
从Java8开始,java.time包提供了新的日期和时间API,主要涉及的类型有:
LocalDate:不包含具体时间的日期。
LocalTime:不含日期的时间。
LocalDateTime:包含了日期及时间。
Instant:代表的是时间戳。
DateTimeFormatter 用于做时间的格式化和解析。
Duration:用于计算两个“时间”间隔。
Period:用于计算两个“日期”间隔。
新增的API严格区分了时刻、本地日期、本地时间,并且,对日期和时间进行运算更加方便。
新API的类型几乎全部是不变类型(和String的使用类似),可以放心使用不必担心被修改。
2.2LocalTime /LocalDate / LocalDateTime
他们分别表示日期,时间,日期时间对象,类的实例是不可变的对象,三者构建对象和API都是通用的。
LocalDate、LocalTime、LocalDateTime构建对象
方法名 | 说明 | |
public static Xxxx.now(); | 静态方法,根据当前时间创建对象 | LocaDate localDate = LocalDate.now(); LocalTime llocalTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now(); |
public static Xxxx.of(…); | 静态方法,指定日期/时间创建对象 | LocalDate localDate1=LocalDate.of(2099, 11, 11); LocalTime localTime1 = LocalTime.of(11, 11, 11); LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43); |
LocalDateTime的转换API
方法名 | 说明 |
public LocalDate toLocalDate() | 转换成一个LocalDate对象 |
public LocalTime toLocalTime() | 转换成一个LocalTime对象 |
修改相关的API
LocalDateTime 综合了LocalDate和LocalTime 里面的方法,所以下面只用LocalDate和LocalTime来举例。
修改相关的API
方法名 | 说明 |
plusDays, plusWeeks, plusMonths, plusYears | 向当前 LocalDate 对象添加几天、几周、几个月、几年 |
minusDays,minusWeeks,minusMonths, minusYears | 从当前 LocalDate 对象减去几天、几周、几个月、几年 |
withDayOfMonth, withDayOfYear, withMonth, withYear | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的LocalDate对象 |
isBefore, isAfter | 比较两个 LocalDate对象 |
注:LocalDateTime、LocalDate、LocalTime都是不可变的,因此这些方法返回的是一个新的对象,原LocalDateTime、LocalDate、LocalTime对象中存储时刻不变。
2.3Instant
JDK8获取时间戳特别简单,且功能更丰富。
如下图所示,Instant类由一个静态的工厂方法now()可以返回当前时间戳。时间戳是包含日期和时间的,与java.util.Date很类似,事实上Instant就是类似JDK8 以前的Date。
Instant和Date这两个类可以进行转换。
2.4DateTimeFormatter
在JDK8中,引入了一个全新的日期与时间格式器DateTimeFormatter。
调用format方法与解析字符串时间为日期时间对象方法如下图所示,其中format方法正反都能调用。
2.5Period/Duration
Period
如下图所示,在Java8中,我们可以使用以下类来计算日期间隔差异:java.time.Period
主要是 Period 类方法 getYears(),getMonths() 和 getDays() 来计算,只能精确到年月日,用于 LocalDate 之间的比较。
Duration
如下图所示,在Java8中,我们可以使用以下类来计算时间间隔差异:java.time.Duration
提供了使用基于时间的值测量时间量的方法,用于 LocalDateTime 之间的比较,也可用于 Instant 之间的比较。
注:Period是比较两个时间差xx年xx月xx天(满量程会进一),如2021.年1月1日至2022年1月10日,period.getYears()为1,period.getMonths()为0,period.getDays()为9,最终结果是三者的结合。
Duration是比较两个时间差多少具体时间,如2022年1月10日 0:00:00至2022年1月10日 1:06:07,duration.toHours()为1,duration.toMinutes()为66,duration.toMillis()为3967000,分别计算。
2.6ChronoUnit
java.time.temporal.ChronoUnit
如下图所示,ChronoUnit类可用于测量两个时刻的时间间隔,这个工具类是最全的了,可以用于比较所有的时间单位。
3.包装类
包装类就是8种基本数据类型对应的引用类型。
基本数据类型与引用数据类型的对应关系
基本数据类型 | 引用数据类型 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
为什么提供包装类?
Java为了实现一切皆对象,为8种基本类型提供了对应的引用类型。
后面的集合和泛型也只能支持包装类型,不支持基本数据类型。
自动装箱:基本类型的数据和变量可以直接赋值给包装类型的变量。
自动拆箱:包装类型的变量可以直接赋值给基本数据类型的变量。
包装类的特有功能
包装类的变量的默认值可以是null,容错率更高。
可以把基本类型的数据转换成字符串类型(用处不大)
①调用toString()方法得到字符串结果。
②调用Integer.toString(基本类型的数据)。
把字符串类型的数值转换成真实的数据类型
① Integer.parseInt(“字符串类型的整数”)
② Double.parseDouble(“字符串类型的小数”)
③也可以用valueOf()方法代替以上两个方法,谁调的方法就转成谁的类型。
示例代码如下:
public static void main(String[] args) {
int a = 10;
Integer a1 = 11;
Integer a2 = a; // 自动装箱
int a3 = a1; // 自动拆箱
System.out.println(a2); // 10
System.out.println(a3); // 11
// int age = null; // 报错,null是引用类型的取值,基本类型不支持
Integer age = null;
System.out.println("--------");
// 包装类可以把基本数据类型的数据转换为字符串形式
Integer i = 23;
String rs = i.toString(); // 调用toString()方法得到字符串结果
System.out.println(rs + 1); // 231 " + " 在字符串运算中作连接符
String rs2 = Integer.toString(i); // 调用Integer.toString(基本类型的数据)
// 把字符串类型的数值转换成真实的数据类型
String number = "123";
System.out.println(number + 1); // 1231 number为String引用数据类型,做连接
int number2 = Integer.parseInt(number);
System.out.println(number2 + 1); // 124 number2为基本数据类型,做求和计算
String score = "99.5";
System.out.println(score + 0.5); // 99.50.5
double score2 = Double.parseDouble(score);
System.out.println(score2 + 0.5); // 100.0
// 也可以用valueOf()方法代替以上两个方法,谁调的方法就转成谁的类型
int number3 = Integer.valueOf(number);
System.out.println(number3);
double score3 = Double.valueOf(score);
System.out.println(score3);
}
4.正则表达式
正则表示
正则表达式可以用一些规定的字符来制定规则,并用来校验数据格式的合法性。
需求:假如现在要求校验一个qq号码是否正确,6位及20位之内,必须全部是数字。先使用目前所学知识完成校验需求,然后使用正则表达式检验。
示例代码如下:
public static void main(String[] args) {
System.out.println(checkQQ(null)); // false
System.out.println(checkQQ("")); // false
System.out.println(checkQQ("12345678")); // true
System.out.println(checkQQ("123456789876543210123456")); // false
System.out.println("------正则表达式------");
System.out.println(checkQQ2(null)); // false
System.out.println(checkQQ2("")); // false
System.out.println(checkQQ2("12345678")); // true
System.out.println(checkQQ2("123456789876543210123456")); // false
}
public static boolean checkQQ(String qq) {
// 判断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') { // 因为字符型每个字符都有对应的ASCⅡ编号,在比较数值大小时要与实际值对应的编号(而不是实际值作为编号)进行比较,因此要带单引号
return false;
}
}
return true;
}
// 正则表达式
public static boolean checkQQ2(String qq) {
return qq != null && qq.matches("\\d{6,20}");
}
字符串对象提供了匹配正则表达式的方法
public boolean matches (String regex):判断是否匹配正则表达式,匹配返回true,不匹配返回false。
正则表达式书写规则如下图所示。
其中X代表正则表达式。
示例代码如下:
public static void main(String[] args) {
// 判断是否为数字、字母、下划线、至少6位
System.out.println("dasdsad1232".matches("\\w{6,}")); // true
System.out.println("25F8".matches("\\w{6,}")); // false
System.out.println("-----------");
// 判断是否为数字、字母,四位
System.out.println("Q".matches("[a-zA-Z0-9]")); // true
System.out.println("29fQ".matches("[a-zA-Z0-9]{4}")); // true 校验多个字符的字符串必须要加上贪婪的量词
System.out.println("29_Q".matches("[a-zA-Z0-9]{4}")); // false
System.out.println("29fQ".matches("[\\w&&[^_]]{4}")); // true
System.out.println("29_Q".matches("[\\w&&[^_]]{4}")); // false
}
注:校验多个字符的字符串必须要加上贪婪的量词。
案例
需求:
①请编写程序模拟用户输入手机号码、验证格式正确,并给出提示,直到格式输入正确为止。
②请编写程序模拟用户输入邮箱号码、验证格式正确,并给出提示,直到格式输入正确为止。
③请编写程序模拟用户输入电话号码、验证格式正确,并给出提示,直到格式输入正确为止。
分析:
定义方法,接收用户输入的数据,使用正则表达式完成检验,并给出提示。
示例代码如下:
public class RegexTest3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// // 校验手机号
// boolean phoneNumberIsRight = false;
// while (phoneNumberIsRight == false) {
// System.out.println("请输入手机号:");
// String phoneNumber = sc.next();
// phoneNumberIsRight = checkPhone(phoneNumber);
// }
// // 校验邮箱号
// boolean EmailIsRight = false;
// while (EmailIsRight == false) {
// System.out.println("请输入邮箱号:");
// String Email = sc.next();
// EmailIsRight = checkEmail(Email);
// }
// 校验电话号
boolean telIsRight = false;
while (telIsRight == false) {
System.out.println("请输入电话号:");
String tel = sc.next();
telIsRight = checkTel(tel);
}
}
/**
* create by: 全聚德在逃烤鸭、
* description: 校验手机号
* create time: 2022/4/22 0022 9:23
*
* @param phoneNumber
* @return boolean
*/
public static boolean checkPhone(String phoneNumber) {
// 判断手机号码的格式是否正确
// 电话号码格式 "1" + 3-9的数字 + 9位数字
if (phoneNumber.matches("1[3-9]\\d{9}")) { // 第一位为1,第二位为3-9其中之一,剩下的为9位的数字
System.out.println("手机号码格式正确");
return true;
} else {
System.out.println("手机号码格式错误,请重新输入!");
return false;
}
}
/**
* create by: 全聚德在逃烤鸭、
* description: 校验邮箱号
* create time: 2022/4/22 0022 9:39
*
* @param Email
* @return boolean
*/
public static boolean checkEmail(String Email) {
// 判断邮箱的格式是否正确
/*
主要邮箱格式类型
215435412@qq.com
s21545rFf25@163.com
faf454rRF@sff.com.cn
*/
// 判断条件:分为4部分:
// 第一部分:1-30位的任意大小写字母、数字、下划线
// 第二部分:@
// 第三部分:2-20位的任意大小写字母、数字
// 第四部分:1-2次的("." + 2-20位的任意大小写字母、数字) 不能直接写".",会当作任意字符
if (Email.matches("\\w{1,30}@[\\w&&[^_]]{2,20}(\\.[\\w&&[^_]]{2,20}){1,2}")) {
System.out.println("邮箱格式正确");
return true;
} else {
System.out.println("邮箱格式错误,请重新输入!");
return false;
}
}
/**
* create by: 全聚德在逃烤鸭、
* description: 校验电话号码
* create time: 2022/4/22 0022 9:42
*
* @param tel
* @return boolean
*/
public static boolean checkTel(String tel) {
// 判断电话号码的格式是否正确
// 电话号码格式 "0" + 2-3位的数字 + -(可有可无) + 5-20位数字
if (tel.matches("0\\d{2,3}-?\\d{5,20}")) { // 第一位为1,第二位为3-9其中之一,剩下的为9位的数字
System.out.println("电话号码格式正确");
return true;
} else {
System.out.println("电话号码格式错误,请重新输入!");
return false;
}
}
}
正则表达式在字符串方法中的使用
方法名 | 说明 |
public String replaceAll(String regex,String newStr) | 按照正则表达式匹配的内容进行替换 |
public String[] split(String regex) | 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。 |
示例代码如下:
public static void main(String[] args) {
// 1. public String replaceAll(String regex,String newStr) 按照正则表达式匹配的内容进行替换
String str = "光明小学424sds_f二年级faf_s45_45SDA一班d45F";
String strNew = str.replaceAll("\\w+", " "); // 将大小写字母、数字、下划线替换为空格
System.out.println(strNew); // 光明小学 二年级 一班
// 2. public String[] split(String regex) 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组
String name = "张三sraga89f李四sf546af王五";
String[] names = name.split("\\w+");
System.out.print("[");
for (int i = 0; i < names.length; i++) {
System.out.print(i == names.length - 1 ? names[i] : names[i] + ",");
}
System.out.println("]"); // [张三,李四,王五]
}
5.Arrays类
Arrays类概述
数组操作工具类,专门用于操作数组元素的。
Arrays常用API
方法名 | 说明 |
public static String toString(类型[] a) | 返回数组的内容(字符串形式) |
public static void sort(类型[] a) | 对数组进行默认升序排序 |
public static <T> void sort(类型[] a, Comparator<? super T> c) | 使用比较器对象自定义排序 |
public static int binarySearch(int[] a, int key) | 二分搜索(前提是数组必须排好序)数组中的数据,存在返回索引,不存在返回-(应该插入位置的索引 + 1) |
自定义排序规则
设置Comparator接口对应的比较器对象,来定制比较规则,比较规则如下图所示。
示例代码如下:
Student类
public class Student {
private String name;
private int age;
private double 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 +
'}';
// getter、setter
}
测试类
public class ArraysDemo1 {
public static void main(String[] args) {
// 1. public static String toString(类型[] a) 返回数组的内容(字符串形式)
int[] arr = {10, 20, 33, 84, 63};
System.out.println(arr); // [I@1540e19d
String rs = Arrays.toString(arr);
System.out.println(rs); // [10, 20, 33, 84, 63]
//2. public static void sort(类型[] a) 对数组进行默认升序排序
Arrays.sort(arr); // 对数组进行默认升序排序
System.out.println(Arrays.toString(arr)); // [10, 20, 33, 63, 84]
//3. public static int binarySearch(int[] a, int key) 二分搜索(前提是数组必须排好序)数组中的数据,存在返回索引,不存在返回-(应该插入位置的索引 + 1)
int index = Arrays.binarySearch(arr, 63); // 使用二分搜索查找63
System.out.println(index); // 3
int index2 = Arrays.binarySearch(arr, 99); // 使用二分搜索查找90
System.out.println(index2); // -6
int index3 = Arrays.binarySearch(arr, 19); // 使用二分搜索查找90
System.out.println(index3); // -2
// 4.public static <T> void sort(类型[] a, Comparator<? super T> c) 使用比较器对象自定义排序
// Arrays的sort方法对于默认有值特性的数组是升序排序
// 自定义规则排序(自定义比较器对象,只能支持引用类型的排序)
Integer[] ages = {34, 12, 42, 23};
/*
参数一:被排序的数组,必须是引用数据类型
参数二:匿名内部类对象,代表一个比较器对象
*/
Arrays.sort(ages, new Comparator<Integer>() {
@Override
// 若返回正整数,则将o1排到后面,若返回负整数,则将o2排到后面
public int compare(Integer o1, Integer o2) {
// 自定义比较规则
return o2 - o1; // 降序排序
}
});
System.out.println(Arrays.toString(ages)); // [42, 34, 23, 12]
System.out.println("--------------");
// 对自定义类型数组进行排序
Student[] students = new Student[3];
students[0] = new Student("张三", 18, 185.3);
students[1] = new Student("李四", 22, 180.5);
students[2] = new Student("王五", 17, 173.5);
System.out.println(Arrays.toString(students));
// [Student{name='张三', age=18, height=185.3}, Student{name='李四', age=22, height=180.5}, Student{name='王五', age=17, height=173.5}]
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge(); // 按年龄升序排序
// return Double.compare(o1.getHeight(), o2.getHeight()); // 按身高升序排序(double类型差值有可能不为整数,但返回值要求必须为整数,可以调用Double类中的compare()方法进行比较,返回整数)
}
});
System.out.println(Arrays.toString(students));
// [Student{name='王五', age=17, height=173.5}, Student{name='张三', age=18, height=185.3}, Student{name='李四', age=22, height=180.5}]
}
}
注:Comparator排序规则,若返回正整数,则将o1排到后面,若返回负整数,则将o2排到后面。
6.常选择排序见算法
6.1选择排序的思想
如下图所示,每轮选择当前位置,开始找出后面的较小值与该位置交换。
选择排序的关键
①确定总共需要选择几轮: 数组的长度-1。
②控制每轮从以前位置为基准,与后面元素选择几次。
示例代码如下:
public static void main(String[] args) {
// 定义数组
int[] arr = {5, 1, 3, 2};
// 定义循环,控制选择几轮 arr.length - 1
int temp; // 临时变量,由于交换数据时临时存储数据
for (int i = 0; i < arr.length - 1; i++) {
// 定义内部循环,控制每轮比较几次
for (int j = i + 1; j < arr.length; j++) {
// 判断是否有比当前第i位数字值更小的数字
if (arr[j] < arr[i]) { // 若存在,则交换二者位置
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 5]
}
6.2二分搜索
二分搜索(前提是数组必须升序排好)数组中的数据,存在返回索引,不存在返回-(应该插入位置的索引 + 1)
数组二分搜索的实现步骤:
①定义变量记录左边和右边位置;
②使用while循环控制查询(条件是左边位置<=右边位置);
③循环内部获取中间元素索引;
④判断当前要找的元素如果大于中间元素,左边位置=中间索引+1;
⑤判断当前要找的元素如果小于中间元素,右边位置=中间索引-1;
⑥判断当前要找的元素如果等于中间元素,返回当前中间元素索引。
示例代码如下:
public class BinarySearch {
public static void main(String[] args) {
// 定义数组
int[] arr = {10, 14, 16, 25, 28, 30, 35, 80, 100};
// 0 1 2 3 4 5 6 7 8
System.out.println(binarySearch(arr, 10)); // 0
System.out.println(binarySearch(arr, 30)); // 5
System.out.println(binarySearch(arr, 18)); // -1
System.out.println(binarySearch(arr, 150)); // -1
}
/**
* create by: 全聚德在逃烤鸭、
* description: 数组二分搜索排序
* create time: 2022/4/30 0030 10:07
*
* @param arr 被搜索的数组
* @param data 搜索的数据
* @return int 搜索数据对应索引/-1
*/
public static int binarySearch(int[] arr, int data) {
// 定义左边位置和右边位置
int left = 0;
int right = arr.length - 1;
// 定义循环,二分搜索
while (left <= right) {
// 取中间位置索引
int middleIndex = (right + left) / 2;
// 比较当前中间索引位置数据值与搜索的数据值的大小
if (arr[middleIndex] == data) { // 若相等,则说明找到该元素,将中间位置索引返回
return middleIndex;
} else if (arr[middleIndex] > data) { // 当前中间索引位置数据值大于搜索的数据值,说明搜索元素在当前中间位置左侧,则舍弃当前中间索引位置右边部分,重新搜索
right = middleIndex - 1;
} else { // 当前中间索引位置数据值小于搜索的数据值,说明搜索元素在当前中间位置右侧,则舍弃当前中间索引位置左边部分,重新搜索
left = middleIndex + 1;
}
}
return -1; // 说明搜索完毕,未找到对应数据,返回-1
}
}
7.Lambda表达式
Lambda概述
Lambda表达式是JDK 8开始后的一种新语法形式。
作用:简化匿名内部类的代码写法。
Lambda表达式的简化格式如下图所示。
注意:Lambda表达式只能简化函数式接口的匿名内部类的写法形式。
什么是函数式接口?
必须是接口,接口中有且仅有一个抽象方法的形式。
通常会在接口上方加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口。
示例代码如下:
public class LambdaDemo1 {
public static void main(String[] args) {
Swimming s1 = new Swimming() {
@Override
public void swim() {
System.out.println("学生游泳");
}
};
go(s1);
System.out.println("---------");
// 使用Lambda表达式简化函数式接口的匿名内部类的写法形式
go(() -> {
System.out.println("老师游泳");
});
}
public static void go(Swimming s) {
System.out.println("开始游泳");
s.swim();
System.out.println("结束游泳");
}
}
@FunctionalInterface
// 加上此注解,代表接口是函数式接口,里面有且只有一个抽象方法
interface Swimming {
public void swim();
}
Lambda的好处?
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,它可以写出更简洁、更灵活的代码,作为一种更紧凑的代码风格,使Java语言表达能力得到了提升。
Lambda表达式的省略写法(在Lambda表达式的基础上进一步简化)
①参数类型可以省略不写。
②如果只有一个参数,参数类型可以省略,同时()也可以省略不写。
③如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号。
④如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写。
写在最后:
感谢读完!
纵然缓慢,驰而不息!加油!