javaSE-API工具类和算法

第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 获取 TimeZonegetDefault 基于程序运行所在的时区创建 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 类是一个抽象类,它为特定瞬间与一组诸如 YEARMONTHHOUR_OF_DAYHOUR日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。与其他语言环境敏感类一样,Calendar 提供了一个类方法 getInstance,以获得此类型的一个通用的对象。

修改和获取 YEARMONTHHOUR_OF_DAYHOUR日历字段对应的时间值。

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类用于计算两个日期(通常是LocalDateLocalDateTimeZonedDateTime的日期部分)之间的间隔。

  • 它通常用于表示以年、月和日为单位的时间量,如“3年2个月1天”。

Duration:用于计算两个“时间”间隔

  • Duration类用于计算两个时间点(通常是LocalTimeLocalDateTimeZonedDateTime的时间部分)之间的间隔。

  • 它通常用于表示以秒和纳秒为单位的时间量,可以转换为其他的时间单位,如毫秒、分钟、小时等。

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]))

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值