第10章 API与常见算法
10.1 和数学相关的类
10.1.1 java.lang.Math
java.lang.Math
类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。类似这样的工具类,其所有方法均为静态方法,并且不会创建对象,调用起来非常简单。
-
public static double abs(double a)
:返回 double 值的绝对值。
double d1 = Math.abs(-5); //d1的值为5 double d2 = Math.abs(5); //d2的值为5
-
public static double ceil(double a)
:返回大于等于参数的最小的整数。
double d1 = Math.ceil(3.3); //d1的值为 4.0 double d2 = Math.ceil(-3.3); //d2的值为 -3.0 double d3 = Math.ceil(5.1); //d3的值为 6.0
-
public static double floor(double a)
:返回小于等于参数最大的整数。
double d1 = Math.floor(3.3); //d1的值为3.0 double d2 = Math.floor(-3.3); //d2的值为-4.0 double d3 = Math.floor(5.1); //d3的值为 5.0
-
public static long round(double a)
:返回最接近参数的 long。(相当于四舍五入方法)
long d1 = Math.round(5.5); //d1的值为6.0 long d2 = Math.round(5.4); //d2的值为5.0
-
public static double pow(double a,double b):返回a的b幂次方法
-
public static double sqrt(double a):返回a的平方根
-
public static double random():返回[0,1)的随机值
-
public static final double PI:返回圆周率
-
public static double max(double x, double y):返回x,y中的最大值
-
public static double min(double x, double y):返回x,y中的最小值
double result = Math.pow(2,31); double sqrt = Math.sqrt(256); double rand = Math.random(); double pi = Math.PI;
10.1.2 java.math包
(1)BigInteger
BigInteger
用于表示任意大小的整数。由于 Java 中的基本数据类型(如 int
, long
)有固定的范围和大小,因此当需要处理超出这些范围的大整数时,BigInteger
就变得非常有用。
-
BigInteger(String val)
-
BigInteger add(BigInteger val)
-
BigInteger subtract(BigInteger val)
-
BigInteger multiply(BigInteger val)
-
BigInteger divide(BigInteger val)
-
BigInteger remainder(BigInteger val)
-
....
public void test01(){ // long bigNum = 123456789123456789123456789L; BigInteger b1 = new BigInteger("123456789123456789123456789"); BigInteger b2 = new BigInteger("78923456789123456789123456789"); // System.out.println("和:" + (b1+b2));//错误的,无法直接使用+进行求和 System.out.println("和:" + b1.add(b2)); System.out.println("减:" + b1.subtract(b2)); System.out.println("乘:" + b1.multiply(b2)); System.out.println("除:" + b2.divide(b1)); System.out.println("余:" + b2.remainder(b1)); }
(2)BigDecimal
BigDecimal
用于处理任意精度的十进制数。提供了任意精度的有符号十进制数字的表示,以及对这些数字进行算术运算的方法。
-
BigDecimal(String val)
-
BigDecimal add(BigDecimal val)
-
BigDecimal subtract(BigDecimal val)
-
BigDecimal multiply(BigDecimal val)
-
BigDecimal divide(BigDecimal val)
-
BigDecimal divide(BigDecimal divisor, int roundingMode)
-
BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
-
BigDecimal remainder(BigDecimal val)
-
....
public void test02(){ /*double big = 12.123456789123456789123456789; System.out.println("big = " + big);*/ BigDecimal b1 = new BigDecimal("123.45678912345678912345678912345678"); BigDecimal b2 = new BigDecimal("7.8923456789123456789123456789998898888"); // System.out.println("和:" + (b1+b2));//错误的,无法直接使用+进行求和 System.out.println("和:" + b1.add(b2)); System.out.println("减:" + b1.subtract(b2)); System.out.println("乘:" + b1.multiply(b2)); System.out.println("除:" + b1.divide(b2,20,RoundingMode.UP));//divide(BigDecimal divisor, int scale, int roundingMode) System.out.println("除:" + b1.divide(b2,20,RoundingMode.DOWN));//divide(BigDecimal divisor, int scale, int roundingMode) System.out.println("余:" + b1.remainder(b2)); }
(3)RoundingMode枚举类
如果项目对精度要求比较高所以使用到Bigdecimal,又涉及到范围限制,所以就涉及到如果除不尽是Bigdecimal的舍人模式的问题
CEILING :向正无限大方向舍入的舍入模式。
DOWN :向零方向舍入的舍入模式。
FLOOR:向负无限大方向舍入的舍入模式。
HALF_DOWN :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。
HALF_EVEN:向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
HALF_UP:向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。
UNNECESSARY:用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。 UP:远离零方向舍入的舍入模式。
10.1.3 java.util.Random
用于产生随机数
-
boolean nextBoolean():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 boolean 值。
-
void nextBytes(byte[] bytes):生成随机字节并将其置于用户提供的 byte 数组中。
-
double nextDouble():返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 double 值。
-
float nextFloat():返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之间均匀分布的 float 值。
-
double nextGaussian():返回下一个伪随机数,它是取自此随机数生成器序列的、呈高斯(“正态”)分布的 double 值,其平均值是 0.0,标准差是 1.0。
-
int nextInt():返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。
-
int nextInt(int n):返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
-
long nextLong():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。
public void test03(){ Random r = new Random(); System.out.println("随机整数:" + r.nextInt()); System.out.println("随机小数:" + r.nextDouble()); System.out.println("随机布尔值:" + r.nextBoolean()); }
10.2 日期时间API
10.2.1 JDK1.8之前
1、java.util.Date
new Date():当前系统时间
long getTime():返回该日期时间对象距离1970-1-1 0.0.0 0毫秒之间的毫秒值 时间戳
new Date(long 毫秒):把该毫秒值换算成日期时间对象
public void test5(){ long time = Long.MAX_VALUE; Date d = new Date(time); System.out.println(d); } public void test4(){ long time = 1559807047979L; Date d = new Date(time); System.out.println(d); } public void test3(){ Date d = new Date(); long time = d.getTime(); System.out.println(time);//1559807047979 } public void test2(){ long time = System.currentTimeMillis(); System.out.println(time);//1559806982971 //当前系统时间距离1970-1-1 0:0:0 0毫秒的时间差,毫秒为单位 } public void test1(){ Date d = new Date(); System.out.println(d); }
2、java.text.SimpleDateFormat
SimpleDateFormat用于日期时间的格式化。
public void test10() throws ParseException{ String str = "2019年06月06日 16时03分14秒 545毫秒 星期四 +0800"; SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒 E Z"); Date d = sf.parse(str); System.out.println(d); } public void test9(){ Date d = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒 E Z"); //把Date日期转成字符串,按照指定的格式转 String str = sf.format(d); System.out.println(str); }
3、java.util.TimeZone
通常,使用 getDefault
获取 TimeZone
,getDefault
基于程序运行所在的时区创建 TimeZone
。
也可以用 getTimeZone
及时区 ID 获取 TimeZone
。例如美国太平洋时区的时区 ID 是 "America/Los_Angeles"。
import org.junit.Test; import java.util.TimeZone; public class TestTimezone { public void test1(){ String[] all = TimeZone.getAvailableIDs(); for (int i = 0; i < all.length; i++) { System.out.println(all[i]); } } public void test2(){ TimeZone t = TimeZone.getTimeZone("America/Los_Angeles"); System.out.println(t); } }
常见时区ID:
Asia/Shanghai UTC America/New_York
4、java.util.Locale
Locale
对象表示了特定的地理、政治和文化地区。需要 Locale
来执行其任务的操作称为语言环境敏感的 操作,它使用 Locale
为用户量身定制信息。
语言参数是一个有效的 ISO 语言代码。这些代码是由 ISO-639 定义的小写两字母代码。
国家/地区参数是一个有效的 ISO 国家/地区代码。这些代码是由 ISO-3166 定义的大写两字母代码。
Locale
类提供了一些方便的常量,可用这些常量为常用的语言环境创建 Locale
对象。
import org.junit.Test; import java.util.Locale; public class TestLocale { public void test01(){ Locale[] all = Locale.getAvailableLocales(); for (int i = 0; i < all.length; i++) { System.out.println(all[i]); } } public void test02(){ Locale 410000 = Locale.410000; System.out.println("410000 = " + 410000); } }
5、java.util.Calendar
Calendar
类是一个抽象类,它为特定瞬间与一组诸如 YEAR
、MONTH
、HOUR_OF_DAY
、HOUR
等 日历字段
之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。与其他语言环境敏感类一样,Calendar
提供了一个类方法 getInstance
,以获得此类型的一个通用的对象。
修改和获取 YEAR
、MONTH
、HOUR_OF_DAY
、HOUR
等 日历字段
对应的时间值。
void add(int field,int amount) 根据给定的日历字段和对应的时间,来对当前的日历进行操作 int get(int field) 获取当前日历的年月日 void set(int field, int value) 设置当前日历的年月日
示例代码:
import org.junit.Test; import java.util.Calendar; import java.util.TimeZone; public class TestCalendar { public void test1(){ Calendar c = Calendar.getInstance(); System.out.println(c); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH)+1; int day = c.get(Calendar.DATE); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute); } public void test2(){ TimeZone t = TimeZone.getTimeZone("America/Los_Angeles"); Calendar c = Calendar.getInstance(t); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH)+1; int day = c.get(Calendar.DATE); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute); } }
10.2.2 JDK1.8之后
Java1.0中包含了一个Date类,但是它的大多数方法已经在Java 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:
-
可变性:象日期和时间这样的类对象应该是不可变的。Calendar类中可以使用三种方法更改日历字段:set()、add() 和 roll()。
-
偏移性:Date中的年份是从1900开始的,而月份都是从0开始的。
-
格式化:格式化只对Date有用,Calendar则不行。
-
此外,它们也不是线程安全的,不能处理闰秒等。
可以说,对日期和时间的操作一直是Java程序员最痛苦的地方之一。第三次引入的API是成功的,并且java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。
Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。
-
java.time – 包含值对象的基础包
-
java.time.chrono – 提供对不同的日历系统的访问。
-
java.time.format – 格式化和解析时间和日期
-
java.time.temporal – 包括底层框架和扩展特性
-
java.time.zone – 包含时区支持的类
Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于时钟(Clock),本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。
1、本地日期时间:LocalDate、LocalTime、LocalDateTime
方法 | 描述 |
---|---|
now() / now(ZoneId zone) | 静态方法,根据当前时间创建对象/指定时区的对象 |
of() | 静态方法,根据指定日期/时间创建对象 |
getDayOfMonth()/getDayOfYear() | 获得月份天数(1-31) /获得年份天数(1-366) |
getDayOfWeek() | 获得星期几(返回一个 DayOfWeek 枚举值) |
getMonth() | 获得月份, 返回一个 Month 枚举值 |
getMonthValue() / getYear() | 获得月份(1-12) /获得年份 |
getHours()/getMinute()/getSecond() | 获得当前对象对应的小时、分钟、秒 |
withDayOfMonth()/withDayOfYear()/withMonth()/withYear() | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象 |
with(TemporalAdjuster t) | 将当前日期时间设置为校对器指定的日期时间 |
plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours() | 向当前对象添加几天、几周、几个月、几年、几小时 |
minusMonths() / minusWeeks()/minusDays()/minusYears()/minusHours() | 从当前对象减去几月、几周、几天、几年、几小时 |
plus(TemporalAmount t)/minus(TemporalAmount t) | 添加或减少一个 Duration 或 Period |
isBefore()/isAfter() | 比较两个 LocalDate |
isLeapYear() | 判断是否是闰年(在LocalDate类中声明) |
format(DateTimeFormatter t) | 格式化本地日期、时间,返回一个字符串 |
parse(Charsequence text) | 将指定格式的字符串解析为日期、时间 |
import org.junit.Test; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; public class TestLocalDateTime { public void test7(){ LocalDate now = LocalDate.now(); LocalDate before = now.minusDays(100); System.out.println(before);//2019-02-26 } public void test06(){ LocalDate lai = LocalDate.of(2019, 5, 13); LocalDate go = lai.plusDays(160); System.out.println(go);//2019-10-20 } public void test05(){ LocalDate lai = LocalDate.of(2019, 5, 13); System.out.println(lai.getDayOfYear()); } public void test04(){ LocalDate lai = LocalDate.of(2019, 5, 13); System.out.println(lai); } public void test03(){ LocalDateTime now = LocalDateTime.now(); System.out.println(now); } public void test02(){ LocalTime now = LocalTime.now(); System.out.println(now); } public void test01(){ LocalDate now = LocalDate.now(); System.out.println(now); } }
2、指定时区日期时间:ZondId和ZonedDateTime
-
ZondId:获取所有可用的时区ID:
-
ZonedDateTime:用于表示带有时区的日期和时间
常见时区ID:
Asia/Shanghai UTC America/New_York
-
Asia/Shanghai
:这是中国的时区标识符,表示上海时间,也就是中国标准时间(CST)。它基于东八区,比协调世界时(UTC)快8小时。 -
UTC
:这是协调世界时(Coordinated Universal Time)的缩写,是一种国际标准时间。UTC 是基于原子时,并且不随季节变化。它被广泛用于全球时间的同步和计算。 -
America/New_York
:这是纽约(美国)的时区标识符,表示北美东部时间(EST)。它基于西五区,在标准时间下比UTC慢5小时。然而,纽约也实行夏令时(EDT),在夏令时期间比UTC慢4小时。
import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Set; public class TestZone { public void test01() { //需要知道一些时区的id //Set<String>是一个集合,容器 //Ctrl+Alt+V 自动创建变量(new 对象();之后选择按快捷键) Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); //快捷模板iter for (String availableZoneId : availableZoneIds) { System.out.println(availableZoneId); } } public void test02(){ ZonedDateTime t1 = ZonedDateTime.now(); System.out.println(t1); ZonedDateTime t2 = ZonedDateTime.now(ZoneId.of("America/New_York")); System.out.println(t2); } }
3、持续日期/时间:Period和Duration
Period:用于计算两个“日期”间隔
-
Period
类用于计算两个日期(通常是LocalDate
、LocalDateTime
或ZonedDateTime
的日期部分)之间的间隔。 -
它通常用于表示以年、月和日为单位的时间量,如“3年2个月1天”。
Duration:用于计算两个“时间”间隔
-
Duration
类用于计算两个时间点(通常是LocalTime
、LocalDateTime
或ZonedDateTime
的时间部分)之间的间隔。 -
它通常用于表示以秒和纳秒为单位的时间量,可以转换为其他的时间单位,如毫秒、分钟、小时等。
import org.junit.Test; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Period; public class TestPeriodDuration { public void test01(){ LocalDate t1 = LocalDate.now(); LocalDate t2 = LocalDate.of(2018, 12, 31); Period between = Period.between(t1, t2); System.out.println(between); System.out.println("相差的年数:"+between.getYears()); System.out.println("相差的月数:"+between.getMonths()); System.out.println("相差的天数:"+between.getDays()); System.out.println("相差的总数:"+between.toTotalMonths()); } public void test02(){ LocalDateTime t1 = LocalDateTime.now(); LocalDateTime t2 = LocalDateTime.of(2017, 8, 29, 0, 0, 0, 0); Duration between = Duration.between(t1, t2); System.out.println(between); System.out.println("相差的总天数:"+between.toDays()); System.out.println("相差的总小时数:"+between.toHours()); System.out.println("相差的总分钟数:"+between.toMinutes()); System.out.println("相差的总秒数:"+between.getSeconds()); System.out.println("相差的总毫秒数:"+between.toMillis()); System.out.println("相差的总纳秒数:"+between.toNanos()); System.out.println("不够一秒的纳秒数:"+between.getNano()); } }
4、DateTimeFormatter:日期时间格式化
该类提供了三种格式化方法:
预定义的标准格式。如:ISO_DATE_TIME;ISO_DATE
-
DateTimeFormatter.ISO_DATE_TIME
:完整的日期和时间,例如 "2023-10-23T14:15:30Z" -
DateTimeFormatter.ISO_DATE
:仅日期部分,例如 "2023-10-23"
本地化相关的格式。如:ofLocalizedDate(FormatStyle.MEDIUM)
-
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
:根据Locale的约定,以中等长度格式显示日期。 |
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
-
您可以定义自己的日期和时间格式。这允许您完全控制输出的格式。
import org.junit.Test; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; public class TestDatetimeFormatter { public void test1(){ LocalDateTime now = LocalDateTime.now(); // DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);//2019年6月6日 下午04时40分03秒 // DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);//2019-6-6 16:40:37 // DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);//19-6-6 下午4:40 DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withZone(ZoneId.systemDefault()); String str = df.format(now); System.out.println(str); } public void test2(){ LocalDateTime now = LocalDateTime.now(); DateTimeFormatter df = DateTimeFormatter.ISO_DATE_TIME;//2019-06-06T16:38:23.756 String str = df.format(now); System.out.println(str); } public void test3(){ LocalDateTime now = LocalDateTime.now(); DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒 E 是这一年的D天"); String str = df.format(now); System.out.println(str); } }
10.3 系统相关类
10.3.1 java.lang.System类
系统类中很多好用的方法,其中几个如下:
-
static long currentTimeMillis() :返回当前系统时间距离1970-1-1 0:0:0的毫秒值
-
static void exit(int status) :退出当前系统
-
static void gc() :运行垃圾回收器。
-
static String getProperty(String key):获取某个系统属性,例如:java.version、user.language、user.country、file.encoding、user.name、os.version、os.name等等
import org.junit.Test; public class TestSystem { public void test01(){ long time = System.currentTimeMillis(); System.out.println("现在的系统时间距离1970年1月1日凌晨:" + time + "毫秒"); System.exit(0); System.out.println("over");//不会执行 } public void test02(){ System.out.println(System.getProperty("java.version")); System.out.println(System.getProperty("user.language")); System.out.println(System.getProperty("user.country")); System.out.println(System.getProperty("file.encoding")); System.out.println(System.getProperty("user.name")); System.out.println(System.getProperty("os.version")); System.out.println(System.getProperty("os.name")); } public void test03() throws InterruptedException { for (int i=1; i <=10; i++){ MyDemo my = new MyDemo(i); //每一次循环my就会指向新的对象,那么上次的对象就没有变量引用它了,就成垃圾对象 } //为了看到垃圾回收器工作,我要加下面的代码,让main方法不那么快结束,因为main结束就会导致JVM退出,GC也会跟着结束。 System.gc();//如果不调用这句代码,GC可能不工作,因为当前内存很充足,GC就觉得不着急回收垃圾对象。 //调用这句代码,会让GC尽快来工作。 Thread.sleep(5000); } } class MyDemo{ private int value; public MyDemo(int value) { this.value = value; } @Override public String toString() { return "MyDemo{" + "value=" + value + '}'; } //重写finalize方法,让大家看一下它的调用效果 @Override protected void finalize() throws Throwable { // 正常重写,这里是编写清理系统内存的代码 // 这里写输出语句是为了看到finalize()方法被调用的效果 System.out.println(this+ "轻轻的走了,不带走一段代码...."); } }
10.3.3 java.lang.Runtime类
每个 Java 应用程序都有一个 Runtime
类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime
方法获取当前运行时。 应用程序不能创建自己的 Runtime 类实例。
public static Runtime getRuntime(): 返回与当前 Java 应用程序相关的运行时对象。
public long totalMemory():返回 Java 虚拟机中的内存总量。此方法返回的值可能随时间的推移而变化,这取决于主机环境。
public long freeMemory():回 Java 虚拟机中的空闲内存量。调用 gc 方法可能导致 freeMemory 返回值的增加。
package com.haogu.system; public class TestRuntime { public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); long totalMemory = runtime.totalMemory(); String str = ""; for (int i = 0; i < args.length; i++) { str += i; } long freeMemory = runtime.freeMemory(); System.out.println("总内存:" + totalMemory); System.out.println("空闲内存:" + freeMemory); System.out.println("已用内存:" + (totalMemory-freeMemory)); } }
10.4 数组工具类
10.4.1 java.util.Arrays类
java.util.Arrays数组工具类,提供了很多静态方法来对数组进行操作,而且如下每一个方法都有各种重载形式,以下只列出int[]和Object[]类型的,其他类型的数组依次类推:
-
数组元素拼接
-
static String toString(int[] a) :字符串表示形式由数组的元素列表组成,括在方括号("[]")中。相邻元素用字符 ", "(逗号加空格)分隔。形式为:[元素1,元素2,元素3。。。] static String toString(Object[] a) :字符串表示形式由数组的元素列表组成,括在方括号("[]")中。相邻元素用字符 ", "(逗号加空格)分隔。元素将自动调用自己从Object继承的toString方法将对象转为字符串进行拼接,如果没有重写,则返回类型@hash值,如果重写则按重写返回的字符串进行拼接。
-
-
数组排序
-
static void sort(int[] a) :将a数组按照从小到大进行排序
-
static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
-
static void sort(Object[] a) :根据元素的自然顺序对指定对象数组按升序进行排序。
-
static <T> void sort(T[] a, Comparator<? super T> c) :根据指定比较器产生的顺序对指定对象数组进行排序。
-
-
数组元素的二分查找
-
static int binarySearch(int[] a, int key)
-
static int binarySearch(Object[] a, Object key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数
-
-
数组的复制
-
static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组
-
static <T> T[] copyOf(T[] original,int newLength):根据original原数组复制一个长度为newLength的新数组,并返回新数组
-
static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
-
static <T> T[] copyOfRange(T[] original,int from,int to):复制original原数组的[from,to)构成新数组,并返回新数组
-
-
比较两个数组是否相等
-
static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
-
static boolean equals(Object[] a,Object[] a2):比较两个数组的长度、元素是否完全相同
-
-
填充数组
-
static void fill(int[] a, int val) :用val值填充整个a数组
-
static void fill(Object[] a,Object val):用val对象填充整个a数组
-
static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val值
-
static void fill(Object[] a, int fromIndex, int toIndex, Object val) :将a数组[fromIndex,toIndex)部分填充为val对象
-
import org.junit.Test; import java.text.Collator; import java.util.Arrays; import java.util.Comparator; import java.util.Locale; public class TestArrays { public void test01() { int[] arr = {1, 2, 3, 4, 5}; System.out.println(Arrays.toString(arr)); Student[] students = new Student[3]; students[0] = new Student("张三", 96); students[1] = new Student("李四", 85); students[2] = new Student("王五", 98); System.out.println(Arrays.toString(students)); } public void test02() { int[] arr = {3, 2, 5, 1, 6}; System.out.println("排序前" + Arrays.toString(arr)); Arrays.sort(arr); System.out.println("排序后" + Arrays.toString(arr)); Student[] students = new Student[3]; students[0] = new Student("张三", 96); students[1] = new Student("李四", 85); students[2] = new Student("王五", 98); System.out.println(Arrays.toString(students)); Arrays.sort(students); System.out.println(Arrays.toString(students)); Arrays.sort(students, new Comparator() { @Override public int compare(Object o1, Object o2) { return Collator.getInstance(Locale.410000).compare(((Student) o1).getName(), ((Student) o2).getName()); } }); System.out.println(Arrays.toString(students)); } public void test03() { int[] arr1 = {1, 2, 3, 4, 5}; int[] arr2 = {1, 2, 3, 4, 5}; System.out.println(Arrays.equals(arr1, arr2)); } public void test04() { int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int[] arr2 = Arrays.copyOf(arr1, 5); int[] arr3 = Arrays.copyOfRange(arr1, 3, 8); System.out.println(Arrays.toString(arr2)); System.out.println(Arrays.toString(arr3)); Arrays.fill(arr1, 5, 9, 3); System.out.println(Arrays.toString(arr1)); } }
package com.haogu.arrays; public class Student implements Comparable { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", score=" + score + '}'; } @Override public int compareTo(Object o) { return this.score - ((Student)o).score; } }
10.4.2 java.lang.System类
系统类中很多好用的方法,其中几个如下:
-
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):
从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。常用于数组的插入和删除
import org.junit.Test; import java.util.Arrays; public class TestSystemArrayCopy { public void test01(){ int[] arr1 = {1,2,3,4,5}; int[] arr2 = new int[10]; System.arraycopy(arr1,0,arr2,3,arr1.length); System.out.println(Arrays.toString(arr1)); System.out.println(Arrays.toString(arr2)); } public void test02(){ int[] arr = {1,2,3,4,5}; System.arraycopy(arr,0,arr,1,arr.length-1); System.out.println(Arrays.toString(arr)); } public void test03(){ int[] arr = {1,2,3,4,5}; System.arraycopy(arr,1,arr,0,arr.length-1); System.out.println(Arrays.toString(arr)); } }
10.4.3 数组的算法升华
1、数组的扩容
(1)至于新数组的长度定义多少合适,看实际情况,如果新增的元素个数确定,那么可以增加指定长度,如果新增元素个数不确定,那么可以扩容为原来的1.5倍、2倍等
(2)数组扩容太多会造成浪费,太少会导致频繁扩容,效率低下
import org.junit.Test; import java.util.Arrays; public class TestArrayExpand { public void test01(){ int[] arr = {1,2,3,4,5}; arr = Arrays.copyOf(arr, arr.length+1); System.out.println(Arrays.toString(arr)); } public void test02(){ int[] arr = {1,2,3,4,5}; // arr = Arrays.copyOf(arr, (int)(arr.length*1.5)); arr = Arrays.copyOf(arr, arr.length + (arr.length>>1)); System.out.println(Arrays.toString(arr)); } public void test03(){ int[] arr = {1,2,3,4,5}; arr = Arrays.copyOf(arr, arr.length << 1); System.out.println(Arrays.toString(arr)); } }
2、删除数组[index]位置的元素
package com.haogu.arrays; import org.junit.Test; import java.util.Arrays; public class TestArrayRemove { public void test01(){ String[] strings = {"hello","java","world","haogu","chai"}; int total = strings.length; //删除[0]位置元素 int index = 0; System.arraycopy(strings, index+1,strings, index,total-index-1); strings[--total] = null; System.out.println(Arrays.toString(strings)); //删除[2]位置元素 index = 3; System.arraycopy(strings, index+1,strings, index, total-index-1);; strings[--total] = null; System.out.println(Arrays.toString(strings)); } }
3、数组[index]位置插入新元素
package com.haogu.arrays; import org.junit.Test; import java.util.Arrays; public class TestArrayInsert { public void test01(){ String[] strings = {"hello","java","world",null,null}; int total = 3; //在[0]位置插入"haha" int index = 0; System.arraycopy(strings, index,strings, index+1,total-index); total++; strings[index] = "haha"; System.out.println(Arrays.toString(strings)); } }
10.5 字符串
java.lang.String
类代表字符串。Java程序中所有的字符串文字(例如"abc"
)都可以被看作是实现此类的实例。字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享。
String
类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。
Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持(toString()方法)。
10.5.1 字符串的特点
1、字符串String类型本身是final声明的,意味着我们不能继承String。
2、字符串的对象也是不可变对象,意味着一旦进行修改,就会产生新对象
我们修改了字符串后,如果想要获得新的内容,必须重新接收。
如果程序中涉及到大量的字符串的修改操作,那么此时的时空消耗比较高。可能需要考虑使用StringBuilder或StringBuffer的可变字符序列。
3、String对象内部是用字符数组进行保存的
JDK1.9之前有一个char[] value数组,JDK1.9之后byte[]数组
"abc"
等效于 char[] data={ 'a' , 'b' , 'c' }
。
例如: String str = "abc"; 相当于: char data[] = {'a', 'b', 'c'}; String str = new String(data); // String底层是靠字符数组实现的。
4、String类中这个char[] values数组也是final修饰的,意味着这个数组不可变,然后它是private修饰,外部不能直接操作它,String类型提供的所有的方法都是用新对象来表示修改后内容的,所以保证了String对象的不可变。
5、就因为字符串对象设计为不可变,那么所以字符串有常量池来保存很多常量对象
常量池在方法区。
如果细致的划分:
(1)JDK1.6及其之前:方法区
(2)JDK1.7:堆
(3)JDK1.8:元空间
String s1 = "abc"; String s2 = "abc"; System.out.println(s1 == s2); // 内存中只有一个"abc"对象被创建,同时被s1和s2共享。
10.5.2 构造字符串对象
1、使用构造方法
-
public String()
:初始化新创建的 String对象,以使其表示空字符序列。 -
String(String original)
: 初始化一个新创建的String
对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。 -
public String(char[] value)
:通过当前参数中的字符数组来构造新的String。 -
public String(char[] value,int offset, int count)
:通过字符数组的一部分来构造新的String。 -
public String(byte[] bytes)
:通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。 -
public String(byte[] bytes,String charsetName)
:通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
构造举例,代码如下:
//字符串常量对象 String str = "hello"; // 无参构造 String str1 = new String(); //创建"hello"字符串常量的副本 String str2 = new String("hello"); //通过字符数组构造 char chars[] = {'a', 'b', 'c','d','e'}; String str3 = new String(chars); String str4 = new String(chars,0,3); // 通过字节数组构造 byte bytes[] = {97, 98, 99 }; String str5 = new String(bytes); String str6 = new String(bytes,"GBK");
2、使用静态方法
-
static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String
-
static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String
-
static String valueOf(char[] data) : 返回指定数组中表示该字符序列的 String
-
static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String
-
static String valueOf(xx value):xx支持各种数据类型,返回各种数据类型的value参数的字符串表示形式。
public static void main(String[] args) { char[] data = {'h','e','l','l','o','j','a','v','a'}; String s1 = String.copyValueOf(data); String s2 = String.copyValueOf(data,0,5); int num = 123456; String s3 = String.valueOf(num); System.out.println(s1); System.out.println(s2); System.out.println(s3); }
3、使用""+
任意数据类型与"字符串"进行拼接,结果都是字符串
public static void main(String[] args) { int num = 123456; String s = num + ""; System.out.println(s); Student stu = new Student(); String s2 = stu + "";//自动调用对象的toString(),然后与""进行拼接 System.out.println(s2); }
10.5.3 字符串的对象的个数
1、字符串常量对象
String str1 = "hello";//1个,在常量池中
2、字符串的普通对象和常量对象一起
String str3 = new String("hello"); //str3首先指向堆中的一个字符串对象,然后堆中字符串的value数组指向常量池中常量对象的value数组
3、面试题
String str1 = "hello"; String str2 = new String("hello"); //上面的代码一共有几个字符串对象。 //2个
10.5.4 字符串对象的内存分析
String s; String s = null; String s = ""; String s = new String(); String s = new String(""); String s = "abc"; String s = new String("abc"); char[] arr = {'a','b'}; String s = new String(arr); char[] arr = {'a','b','c','d','e'}; String s = new String(arr,0,3);
10.5.5 字符串拼接问题
1、拼接结果的存储和比较问题
原则:
(1)常量+常量:结果是常量池
(2)常量与变量 或 变量与变量:结果是堆
(3)拼接后调用intern方法:结果在常量池
public void test06(){ String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; String s4 = (s1 + "world").intern();//把拼接的结果放到常量池中 String s5 = (s1 + s2).intern(); System.out.println(s3 == s4);//true System.out.println(s3 == s5);//true } public void test05(){ final String s1 = "hello"; final String s2 = "world"; String s3 = "helloworld"; String s4 = s1 + "world";//s4字符串内容也helloworld,s1是常量,"world"常量,常量+ 常量 结果在常量池中 String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是常量,常量+ 常量 结果在常量池中 String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果 System.out.println(s3 == s4);//true System.out.println(s3 == s5);//true System.out.println(s3 == s6);//true } public void test04(){ String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; String s4 = s1 + "world";//s4字符串内容也helloworld,s1是变量,"world"常量,变量 + 常量的结果在堆中 String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是变量,变量 + 变量的结果在堆中 String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果 System.out.println(s3 == s4);//false System.out.println(s3 == s5);//false System.out.println(s3 == s6);//true }
2、拼接效率问题
public class TestString { public static void main(String[] args) { String str = "0"; for (int i = 0; i <= 5; i++) { str += i; } System.out.println(str); } }
3、两种拼接
public class TestString { public static void main(String[] args) { String str = "hello"; String str2 = "world"; String str3 ="helloworld"; String str4 = "hello".concat("world"); String str5 = "hello"+"world"; System.out.println(str3 == str4);//false System.out.println(str3 == str5);//true } }
concat方法拼接,哪怕是两个常量对象拼接,结果也是在堆。
10.5.6 字符串对象的比较
1、==:比较是对象的地址
只有两个字符串变量都是指向字符串的常量对象时,才会返回true
String str1 = "hello"; String str2 = "hello"; System.out.println(str1 == str2);//true String str3 = new String("hello"); String str4 = new String("hello"); System.out.println(str1 == str4); //false System.out.println(str3 == str4); //false
2、equals:比较是对象的内容,因为String类型重写equals,区分大小写
只要两个字符串的字符内容相同,就会返回true
String str1 = "hello"; String str2 = "hello"; System.out.println(str1.equals(str2));//true String str3 = new String("hello"); String str4 = new String("hello"); System.out.println(str1.equals(str3));//true System.out.println(str3.equals(str4));//true
3、equalsIgnoreCase:比较的是对象的内容,不区分大小写
String str1 = new String("hello"); String str2 = new String("HELLO"); System.out.println(str1.equalsIgnoreCase(strs)); //true
4、compareTo:String类型重写了Comparable接口的抽象方法,自然排序,按照字符的Unicode编码值进行比较大小的,严格区分大小写
String str1 = "hello"; String str2 = "world"; str1.compareTo(str2) //小于0的值
5、compareToIgnoreCase:不区分大小写,其他按照字符的Unicode编码值进行比较大小
String str1 = new String("hello"); String str2 = new String("HELLO"); str1.compareToIgnoreCase(str2) //等于0
10.5.7 空字符的比较
1、哪些是空字符串
String str1 = ""; String str2 = new String(); String str3 = new String("");
空字符串:长度为0
2、如何判断某个字符串是否是空字符串
if("".equals(str)) if(str!=null && str.isEmpty()) if(str!=null && str.equals("")) if(str!=null && str.length()==0)
10.5.8 字符串的常用方法
1、系列1:常用方法
(1)boolean isEmpty():字符串是否为空
(2)int length():返回字符串的长度
(3)String concat(xx):拼接,等价于+
(4)boolean equals(Object obj):比较字符串是否相等,区分大小写
(5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写
(6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小
(7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
(8)String toLowerCase():将字符串中大写字母转为小写
(9)String toUpperCase():将字符串中小写字母转为大写
(10)String trim():去掉字符串前后空白符
(11)public String intern():结果在常量池中共享
2、系列2:查找
(11)boolean contains(xx):是否包含xx
(12)int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1
(13)int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1
public void test01(){ String str = "好谷就业力成长于河南,专注于河南,口碑于河南,拥有自主知识产权的三大实训支持系统(技术系统/能力系统/职业战略),立志为青年学子提供技术与能力并重的职业技能综合发展平台,助力河南学子创造中国互联网未来"; System.out.println("是否包含河南:" + str.contains("河南")); System.out.println("河南出现的第一次下标:" + str.indexOf("河南")); System.out.println("河南出现的最后一次下标:" + str.lastIndexOf("河南")); }
3、系列3:字符串截取
(14)String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
(15)String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
public void test01(){ String str = "helloworldjavahaogu"; String sub1 = str.substring(5); String sub2 = str.substring(5,10); System.out.println(sub1); System.out.println(sub2); } public void test02(){ String fileName = "快速学习Java的秘诀.dat"; //截取文件名 System.out.println("文件名:" + fileName.substring(0,fileName.lastIndexOf("."))); //截取后缀名 System.out.println("后缀名:" + fileName.substring(fileName.lastIndexOf("."))); }
4、系列4:和字符相关
(16)char charAt(index):返回[index]位置的字符
(17)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回
(18)String(char[] value):返回指定数组中表示该字符序列的 String。
(19)String(char[] value, int offset, int count):返回指定数组中表示该字符序列的 String。
(20)static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String
(21)static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String
(22)static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String
(23)static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String
public void test01(){ //将字符串中的字符按照大小顺序排列 String str = "helloworldjavahaogu"; char[] array = str.toCharArray(); Arrays.sort(array); str = new String(array); System.out.println(str); } public void test02(){ //将首字母转为大写 String str = "jack"; str = Character.toUpperCase(str.charAt(0))+str.substring(1); System.out.println(str); }
5、系列5:编码与解码
(24)byte[] getBytes():编码,把字符串变为字节数组,按照平台默认的字符编码方式进行编码
byte[] getBytes(字符编码方式):按照指定的编码方式进行编码
(25)new String(byte[] ) 或 new String(byte[], int, int):解码,按照平台默认的字符编码进行解码
new String(byte[],字符编码方式 ) 或 new String(byte[], int, int,字符编码方式):解码,按照指定的编码方式进行解码
package com.haogu.string; import org.junit.Test; public class StringMethod5 { public void test01()throws Exception{ byte[] data = {(byte)0B11100101, (byte)0B10110000, (byte)0B10011010, (byte)0B11000111, (byte)0B10101011,(byte)0B01110110}; System.out.println(new String(data,"ISO8859-1")); System.out.println(new String(data,"GBK")); System.out.println(new String(data,"UTF-8")); } public void test02() throws Exception { String str = "中国"; System.out.println(str.getBytes("ISO8859-1").length);// 2 // ISO8859-1把所有的字符都当做一个byte处理,处理不了多个字节 System.out.println(str.getBytes("GBK").length);// 4 每一个中文都是对应2个字节 System.out.println(str.getBytes("UTF-8").length);// 6 常规的中文都是3个字节 /* * 不乱码:(1)保证编码与解码的字符集名称一样(2)不缺字节 */ System.out.println(new String(str.getBytes("ISO8859-1"), "ISO8859-1"));// 乱码 System.out.println(new String(str.getBytes("GBK"), "GBK"));// 中国 System.out.println(new String(str.getBytes("UTF-8"), "UTF-8"));// 中国 } }
6、系列6:开头与结尾
(26)boolean startsWith(xx):是否以xx开头
(27)boolean endsWith(xx):是否以xx结尾
public void test2(){ String name = "张三"; System.out.println(name.startsWith("张")); } public void test(){ String file = "Hello.txt"; if(file.endsWith(".java")){ System.out.println("Java源文件"); }else if(file.endsWith(".class")){ System.out.println("Java字节码文件"); }else{ System.out.println("其他文件"); } }
7、系列7:正则匹配
(28)boolean matchs(正则表达式):判断当前字符串是否匹配某个正则表达式。==(正则表达式见附录10.7.2)==
public void test1(){ //简单判断是否全部是数字,这个数字可以是1~n位 String str = "12a345"; //正则不是Java的语法,它是独立与Java的规则 //在正则中\是表示转义, //同时在Java中\也是转义 boolean flag = str.matches("\\d+"); System.out.println(flag); } public void test2(){ String str = "123456789"; //判断它是否全部由数字组成,并且第1位不能是0,长度为9位 //第一位不能是0,那么数字[1-9] //接下来8位的数字,那么[0-9]{8}+ boolean flag = str.matches("[1-9][0-9]{8}+"); System.out.println(flag); } public void test03(){ //密码要求:必须有大写字母,小写字母,数字组成,6位 System.out.println("Cly892".matches("^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])[A-Za-z0-9]{6}$"));//true System.out.println("1A2c45".matches("^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])[A-Za-z0-9]{6}$"));//true System.out.println("Clyyyy".matches("^(?=.*[A-Z])(?=.*[0-9])[A-Za-z0-9]{6}$"));//false }
8、系列8:替换
(29)String replace(xx,xx):不支持正则
(30)String replaceFirst(正则,value):替换第一个匹配部分
(31)String repalceAll(正则, value):替换所有匹配部分
public void test4(){ String str = "hello244world.java;887"; //把其中的非字母去掉 str = str.replaceAll("[^a-zA-Z]", ""); System.out.println(str); }
9、系列9:拆分
(32)String[] split(正则):按照某种规则进行拆分
public void test4(){ String str = "张三.23|李四.24|王五.25"; //|在正则中是有特殊意义,我这里要把它当做普通的| String[] all = str.split("\\|"); //转成一个一个学生对象 Student[] students = new Student[all.length]; for (int i = 0; i < students.length; i++) { //.在正则中是特殊意义,我这里想要表示普通的. String[] strings = all[i].split("\\.");//张三, 23 String name = strings[0]; int age = Integer.parseInt(strings[1]); students[i] = new Student(name,age); } for (int i = 0; i < students.length; i++) { System.out.println(students[i]); } } public void test3(){ String str = "1Hello2World3java4haogu5"; str = str.replaceAll("^\\d|\\d$", ""); String[] all = str.split("\\d"); for (int i = 0; i < all.length; i++) { System.out.println(all[i]); } } public void test2(){ String str = "1Hello2World3java4haogu"; str = str.replaceFirst("\\d", ""); System.out.println(str); String[] all = str.split("\\d"); for (int i = 0; i < all.length; i++) { System.out.println(all[i]); } } public void test1(){ String str = "Hello World java haogu"; String[] all = str.split(" "); for (int i = 0; i < all.length; i++) { System.out.println(all[i]); } }
10.6 可变字符序列
10.6.1 String与可变字符序列的区别
因为String对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低。因此,JDK又在java.lang包提供了可变字符序列StringBuilder和StringBuffer类型。
StringBuffer:老的,线程安全的(因为它的方法有synchronized修饰)
StringBuilder:线程不安全的
10.6.2 StringBuilder、StringBuffer的API
常用的API,StringBuilder、StringBuffer的API是完全一致的
(1)StringBuffer append(xx):拼接,追加
(2)StringBuffer insert(int index, xx):在[index]位置插入xx
(3)StringBuffer delete(int start, int end):删除[start,end)之间字符
StringBuffer deleteCharAt(int index):删除[index]位置字符
(4)void setCharAt(int index, xx):替换[index]位置字符
(5)StringBuffer reverse():反转
(6)void setLength(int newLength) :设置当前字符序列长度为newLength
(7)StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str
(8)int indexOf(String str):在当前字符序列中查询str的第一次出现下标
int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标
int lastIndexOf(String str):在当前字符序列中查询str的最后一次出现下标
int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标
(9)String substring(int start):截取当前字符序列[start,最后]
(10)String substring(int start, int end):截取当前字符序列[start,end)
(11)String toString():返回此序列中数据的字符串表示形式
public void test6(){ StringBuilder s = new StringBuilder("helloworld"); s.setLength(30); System.out.println(s); } public void test5(){ StringBuilder s = new StringBuilder("helloworld"); s.setCharAt(2, 'a'); System.out.println(s); } public void test4(){ StringBuilder s = new StringBuilder("helloworld"); s.reverse(); System.out.println(s); } public void test3(){ StringBuilder s = new StringBuilder("helloworld"); s.delete(1, 3); s.deleteCharAt(4); System.out.println(s); } public void test2(){ StringBuilder s = new StringBuilder("helloworld"); s.insert(5, "java"); s.insert(5, "chailinyan"); System.out.println(s); } public void test1(){ StringBuilder s = new StringBuilder(); s.append("hello").append(true).append('a').append(12).append("haogu"); System.out.println(s); System.out.println(s.length()); }
10.6.3 效率测试
package com.haogu.stringbuffer; import org.junit.Test; public class TestTime { public void testString(){ long start = System.currentTimeMillis(); String s = new String("0"); for(int i=1;i<=10000;i++){ s += i; } long end = System.currentTimeMillis(); System.out.println("String拼接+用时:"+(end-start));//367 long memory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); System.out.println("String拼接+memory占用内存: " + memory);//473081920字节 } public void testStringBuilder(){ long start = System.currentTimeMillis(); StringBuilder s = new StringBuilder("0"); for(int i=1;i<=10000;i++){ s.append(i); } long end = System.currentTimeMillis(); System.out.println("StringBuilder拼接+用时:"+(end-start));//5 long memory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); System.out.println("StringBuilder拼接+memory占用内存: " + memory);//13435032 } public void testStringBuffer(){ long start = System.currentTimeMillis(); StringBuffer s = new StringBuffer("0"); for(int i=1;i<=10000;i++){ s.append(i); } long end = System.currentTimeMillis(); System.out.println("StringBuffer拼接+用时:"+(end-start));//5 long memory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); System.out.println("StringBuffer拼接+memory占用内存: " + memory);//13435032 } }
10.7 正则表达式
常见的正则表达式示例
-
验证用户名和密码,要求第一个字必须为字母,一共6~16位字母数字下划线组成:(^[a-zA-Z]\w{5,15}$)
-
验证电话号码:xxx/xxxx-xxxxxxx/xxxxxxxx:(^(\d{3,4}-)\d{7,8}$)
-
验证手机号码:( ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$ )
-
验证身份证号: (^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
-
验证Email地址:(^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$)
-
只能输入由数字和26个英文字母组成的字符串:(^[A-Za-z0-9]+$)
-
整数或者小数:(^[0-9]+(.[0-9]+){0,1}$)
-
中文字符的正则表达式:([\u4e00-\u9fa5])
-
金额校验(非零开头的最多带两位小数的数字):(^([1-9][0-9]*)+(.[0-9]{1,2})?$)
-
IPV4地址:(((\d{1,2})|(1\d{1,2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{1,2})|(2[0-4]\d)|(25[0-5]))