String类
String类是一个特殊的对象,适用于描述字符串事物的,一旦被初始化就不可以被改变,可以进行字符串的大小写转换,分割字符串等字符串的操作。
String
底层是final
类型的char[]
,是不可修改的。
String str1 = null;// 表示str1没有引用地址
String str2 = "";// 表示str2对象引用了在常量池中创建了一个空字符串常量
String str3 = new String();// 表示str3对象引用了在堆中创建了一个空字符串常量
String str4 = str1 + "a"; // 会创建StringBuilder的新对象,本质是调用了StringBuilder的apend()方法拼接
将其他类型转换为String类型不同方式效率对比:
toString()
> String.valueOf(Object obj)
> +
因为+
号,底层先将字符串对象转换为StringBuilder
对象,然后调用StringBuilder
对象的append
追加字符串方法,再调用toString
方法,转换为String
对象。
常量池
放字符串常量的地方,JDK8后是放在堆中,当创建字符串对象是字面量(直接是= " “)的时候,会优先从常量池中查找,是否有该字符串对象,如果有,则会直接将常量池中的地址赋值给该String对象;如果没有,则会在常量池创建对象,然后将对象常量池的地址给String对象保存。
当创建字符串对象用new创建,会优先从常量池中查找,是否有该字符串对象,如果有,则会直接将常量池中的地址赋值给该String对象在堆中的地址;如果没有,则会在常量池创建对象,然后将对象常量池的地址给String对象在堆中保存
String常用方法
-
length()
字符串的长度char chars[]={'a','b','c'}; String s=new String(chars); int len=s.length();
-
charAt()
截取一个字符char ch; ch="abc".charAt(1); // 返回'b'
-
getChars()
截取多个字符void getChars(int sourceStart,int sourceEnd,char target[],int targetStart)
sourceStart
指定了子串开始字符的下标,sourceEnd
指定了子串结束后的下一个字符的下标。因此, 子串包含从sourceStart
到sourceEnd-1
的字符。接收字符的数组由target
指定,target
中开始复制子串的下标值是targetStart
。String s="this is a demo of the getChars method."; char buf[]=new char[20]; s.getChars(10,14,buf,0);
-
getBytes()
替代
getChars()
的一种方法是将字符存储在字节数组中,该方法即getBytes()。 -
toCharArray()
String
转换成char[]
-
equals()
和equalsIgnoreCase()
比较两个字符串
-
regionMatches()
用于比较一个字符串中特定区域与另一特定区域,它有一个重载的形式允许在比较中忽略大小写。
boolean regionMatches(int startIndex,String str2,int str2StartIndex,int numChars)
boolean regionMatches(boolean ignoreCase,int startIndex,String str2,int str2StartIndex,int numChars)
-
startsWith()
和endsWith()
startsWith()
方法决定是否以特定字符串开始,endWith()
方法决定是否以特定字符串结束 -
equals()
和==
equals()
方法比较字符串对象中的字符,==
运算符比较两个对象是否引用同一实例。String s1="Hello"; String s2=new String(s1); s1.eauals(s2); // true s1==s2; // false
-
compareTo()
和compareToIgnoreCase()
比较字符串,一致则返回0,不一致返回1。
-
contains()
比较是否含有指定字符串。
-
indexOf()
和lastIndexOf()
indexOf()
查找字符或者子串第一次出现的地方。lastIndexOf()
查找字符或者子串是后一次出现的地方。 -
substring()
返回字符串的子字符串,有两种形式
第一种:
String substring(int startIndex)
第二种:
String substring(int startIndex,int endIndex)
-
concat()
连接两个字符串
-
replace()
替换第一种形式用一个字符在调用字符串中所有出现某个字符的地方进行替换,形式如下:
String replace(char original,char replacement)
String s="Hello".replace('l','w');
第二种形式是用一个字符序列替换另一个字符序列,形式如下:
String replace(CharSequence original,CharSequence replacement)
-
trim()
去掉起始和结尾的空格
-
valueOf()
转换为字符串
-
toLowerCase()
转换为小写
-
toUpperCase()
转换为大写
StringBuilder类
StringBuilder
基于可变的char[]
,默认长度是16个字节,适用于频繁操作(增删改插)字符串的场景,该类是线程不安全的。
特点:
- 是一个字符串缓冲区,其实就是一个容器;
- 长度是可变的,任意类型都可以。注意:是将任意数据都转成字符串进行存储;
- 容器对象提供很多对容器中的数据操作的功能,比如添加,删除,修改,查询;
- 所有的数据最终都会变成一个字符串。
StringBuilder类的常用方法
构造方法:
-
StringBuilder()
构造方法,其初始容量为16个字符表示,如果存在StringBuilder
的数据超过了16个字符,这个容器可以自动扩容(容器空间自动变大)。 -
StringBuilder(int capacity)
构造函数来说,capacity表示容器的容量,如果想设置缓冲区大小,可以通过此构造函数来实现。
StringBuilder sb = new StringBuilder();// 创建一个默认16个长度的char[]数组
StringBuilder sb2 = new StringBuilder("abc");// 创建一个19个长度的char[]数组
成员方法:
-
append(String s)
将指定的字符串追加到此字符序列,将根据需要自动分配空间。
StringBuilder MyStringBuilder = new StringBuilder("Hello World!"); MyStringBuilder.append(" What a beautiful day."); System.out.println(MyStringBuilder); // 输出结果:Hello World! What abeautiful day.
-
reverse()
将此字符序列用其反转形式取代。
-
delete(int start, int end)
移除此序列的子字符串中的字符。
-
insert(int offset, int i)
将
int
参数的字符串表示形式插入此序列中。 -
insert(int offset, String str)
将
str
参数的字符串插入此序列中。 -
replace(int start, int end, String str)
使用给定
String
中的字符替换此序列的子字符串中的字符。 -
int capacity()
返回当前容量。 -
char charAt(int index)
返回此序列中指定索引处的 char 值。 -
void ensureCapacity(int minimumCapacity)
确保容量至少等于指定的最小值。 -
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
将字符从此序列复制到目标字符数组 dst。 -
int indexOf(String str)
返回第一次出现的指定子字符串在该字符串中的索引。 -
int indexOf(String str, int fromIndex)
从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。 -
int lastIndexOf(String str)
返回最右边出现的指定子字符串在此字符串中的索引。 -
int lastIndexOf(String str, int fromIndex)
返回 String 对象中子字符串最后出现的位置。 -
int length()
返回长度(字符数)。 -
void setCharAt(int index, char ch)
将给定索引处的字符设置为 ch。 -
void setLength(int newLength)
设置字符序列的长度。 -
CharSequence subSequence(int start, int end)
返回一个新的字符序列,该字符序列是此序列的子序列。 -
String substring(int start)
返回一个新的 String,它包含此字符序列当前所包含的字符子序列。 -
String substring(int start, int end)
返回一个新的 String,它包含此序列当前所包含的字符子序列。
-
String toString()
返回此序列中数据的字符串表示形式。
StringBuffer & StringBuilder类
和 String
类不同的是,StringBuffer
和 StringBuilder
类的对象能够被多次的修改,并且不产生新的未使用对象。
在使用 StringBuffer
类时,每次都会对 StringBuffer
对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer
。
StringBuilder
类在 Java 5 中被提出,它和 StringBuffer
之间的最大不同在于 StringBuilder
的方法不是线程安全的(不能同步访问)。
由于 StringBuilder
相较于 StringBuffer
有速度优势,所以多数情况下建议使用 StringBuilder
类,在应用程序要求线程安全的情况下,则必须使用 StringBuffer
类。
StringBuffer
和StringBuilder
扩容机制:当要添加的字符串大于 > 当前字符数组的长度的时候扩容,扩容是: 原来长度*2+2 的方式扩容
包装类
包装类就是8个基本类型所对应的引用类型,通过包装类中的方法可以提高处理数据的效率。
基本类型 | 包装类 | 父类 | 父类 |
---|---|---|---|
byte | Byte | Number抽象 | Object |
short | Short | Number抽象 | Object |
int | Integer | Number抽象 | Object |
long | Long | Number抽象 | Object |
float | Float | Number抽象 | Object |
double | Double | Number抽象 | Object |
char | Character | Object | 无 |
boolean | Boolean | Object | 无 |
自动装箱:将基本类型隐式转换为对应的包装类就是自动装箱。
自动拆箱:将包装类转换为对应的基本类型就是自动拆箱。
Integer chenmo = new Integer(10); // 手动装箱
int wanger = chenmo.intValue(); // 手动拆箱
Integer chenmo = 10; // 自动装箱
int wanger = chenmo; // 自动拆箱
// JAD 反编译后的结果:
Integer chenmo = Integer.valueOf(10);
int wanger = chenmo.intValue();
享元模式:
必须是使用自动装箱方式(因为自动装箱使用的Integer.valueOf()
方法定义了缓存区,传入的值会先判断是否在缓存范围内),才用享元模式Byte/Short/Integer/Long 都在类的内部通过静态内部类缓存了 -128~127之间的数字,在此范围内并不会创建对象,都是用的静态缓存区的对象地址。
// 1)基本类型和包装类型
int a = 200;
Integer b = 200;
System.out.println(a == b); // 基本类型和包装类型进行 == 比较,这时候 b 会自动拆箱,直接和 a 比较值,所以结果为 true
// 2)两个包装类型
Integer c = 100;
Integer d = 100;
System.out.println(c == d); // 因为享元模式,所以相等,结果为true
// 3)
c = 200;
d = 200;
System.out.println(c == d); // 200 不在-128~127,所以 new 出来了两个 Integer 对象,结果为false
数学相关类 Math/BigInteger/BigDecimal
-
Math:
数学工具类,有很多数学相关运算的方法。如基本指数,对数,平方根和三角函数。
-
abs(double a)
;返回值为 double绝对值。
-
ceil(double a)
向上取整。
System.out.println(Math.ceil(3.14)); // 4.0
-
floor(double a)
向下取整。
System.out.println(Math.floor(3.14)); // 3.0
-
round(double a)
四舍五入。
System.out.println(Math.round(3.45)); // 4
-
max(double a, double b)
返回两个 double值中的较大值。
-
min(double a, double b)
返回两个 double值中的较小值。
-
-
BigInteger:
比long类型精度更高的整数类型,创建对象用String类型参数的构造方法。
-
BigDecimal:
比double类型精度更高的类型,一般使用在金融相关行业。例如,银行、保险公司等。
注:要注意出发溢出问题。如果被除数高位的数值比除数大,那么会产生溢出。
时间相关类
Date类
适用于特定的某一刻时间的场景,指具体某一刻的时间,如:订单时间、入职时间等。
-
构造方法
Date()
创建的就是当前这一刻时间的对象Date(long time)
将指定毫秒数的时间转换为对应的日期时间 距离1970年1月1日 0时0分0秒
-
普通方法
-
long getTime()
获取当前Date对象所对应的long类型的时间毫秒数 -
void setTime(long time)
将当前date对象设置为时间毫秒数time所对应的日期 -
before(Date date)
判断是否在指定日期之前 -
after(Date date)
判断是否在指定日期之后
-
SimpleDateFormat类
用来将Date和String进行格式转换的,可以根据不同的国家地区设置时间格式。
-
构造方法
SimpleDateFormat()
SimpleDateFormat(String pattern)
创建一个含有指定字符串模板的SimpleDateFormat对象
-
将Date转换为String类型
根据模板转换,模板是根据不同地区习惯设置
// 1.创建对象 SimpleDateFormat sdf = new SimpleDateFormat(String 模板); // 2.将Date转换为String sdf.format(date);
-
将String转换为Date类型
// 1.创建对象 SimpleDateFormat sdf = new SimpleDateFormat(String 模板); // 2. 将String转换为Date sdf.parse(str); // 可以将SimpleDateFormat重新设置模板格式 sdf.applyPattern(String pattern);
Calendar日历类
是一个抽象类,可以为在某一特定时刻和一组之间的转换的方法,主要用来操作一段时间和进行时间加减等场景
-
构造方法
Calendar instance = Calendar.getInstance()
由于是抽象类,获取一个对象只能通过子类或者内部提供的方法。 -
注意事项
Calendar
的 month 从 0 开始,也就是全年 12 个月由 0 ~ 11 进行表示。而
Calendar.DAY_OF_WEEK
定义和值从周日开始为1,以此类推,如下:Calendar.SUNDAY = 1
Calendar.MONDAY = 2
Calendar.TUESDAY = 3
Calendar.WEDNESDAY = 4
Calendar.THURSDAY = 5
Calendar.FRIDAY = 6
Calendar.SATURDAY = 7
-
常用方法
-
int get(int field)
获取某一个字段(当前Calendar常量)的时间Calendar instance = Calendar.getInstance(); int year = instance.get(Calendar.YEAR);// 这里就是获取年这个字段的值,使用常量YEAR int month = instance.get(Calendar.MONTH); // 这里就是获取月份这个字段的值 月份是:0-11 int day = instance.get(Calendar.DAY_OF_MONTH); // 这里就是获取月份中的日期这个字段的值 System.out.println(year + "年" + (month + 1) + "月" + day + "日");
-
abstract void add(int field, int amount)
添加时间操作field:是Calendar中的常量。
amount:如果是正数,表示+,如果是负数,就是减。月、日都会导致进位退位,月份从范围0-11,如果月份超过11,则进年,如果日期超过所在月份的最大或者最小一天,则进月或者退月。
Calendar instance = Calendar.getInstance(); instance.add(Calendar.YEAR, 5); // 给年字段+5 // 重新获取年 int year = instance.get(Calendar.YEAR); System.out.println("新的年:" + year); // 将月份-11 instance.add(Calendar.MONTH, -11); // 重新获取年 year = instance.get(Calendar.YEAR); System.out.println("新的年:" + year); // 重新获取月 int month = instance.get(Calendar.MONTH); System.out.println("新的月:" + (month + 1));
-
void set(int field, int value)
可以直接设置某一个字段的值。例如设置年
set(Calendar.YEAR,2050);
-
Date getTime()
将Calendar对象转换为Date类型 -
void setTime(Date date)
将Date转换为CalendarCalendar instance = Calendar.getInstance(); instance.setTime(new Date()); System.out.println(instance);
-
boolean after(Calendar when)
-
boolean before(Calendar when)
-
-
取值
取值当天
public String getThisToday(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY,0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND,0); String start = sdf.format(cal.getTime()); cal.set(Calendar.HOUR_OF_DAY,23); cal.set(Calendar.MINUTE, 59); cal.set(Calendar.SECOND,59); String end = sdf.format(cal.getTime()); return start+"|"+end; }
取值本周
public String getThisWeekDate(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar ca = Calendar.getInstance(); ca.setFirstDayOfWeek(Calendar.MONDAY); ca.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY); ca.set(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH),ca.get(Calendar.DATE),23,59,59); String end = sdf.format(ca.getTime()); ca.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); ca.set(Calendar.HOUR_OF_DAY,0); ca.set(Calendar.MINUTE, 0); ca.set(Calendar.SECOND,0); String start = sdf.format(ca.getTime()); return start+"|"+end; }
取值本月日期段
public String getThisMonthDate(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar cc2 = Calendar.getInstance(); int maxMonthDay = cc2.getActualMaximum(Calendar.DAY_OF_MONTH); cc2.set(cc2.get(Calendar.YEAR), cc2.get(Calendar.MONTH),maxMonthDay,23,59,59); String end = sdf.format(cc2.getTime()); cc2.set(cc2.get(Calendar.YEAR), cc2.get(Calendar.MONTH),1,0,0,0); String start = sdf.format(cc2.getTime()); return start+"|"+end; }
定时器Timer
Timer
可以按计划执行重复的任务或者定时执行指定任务,这是因为 Timer
内部利用了一个后台线程 TimerThread
有计划地执行指定任务。
-
构造方法:
Timer()
创建一个新的定时器对象Timer(String name)
创建一个新的定时器,其相关线程具有指定的名称 -
常用方法:
-
void schedule(TimerTask task, Date time)
在指定的时间执行指定的任务
-
void schedule(TimerTask task, long delay)
在指定的毫秒数之后执行指定的任务。
-
void schedule(TimerTask task, Date firstTime, long period)
从指定的时间开始 ,间隔指定的毫秒数重复的执行
-
void schedule(TimerTask task, long delay, long period)
从指定的时间延迟后 ,间隔指定的毫秒数重复的执行
-
void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
从指定的时间开始 ,间隔指定的毫秒数重复的执行(如果当Time是过去时间,会一次性将所有缺少的任务执行完毕)
-
void scheduleAtFixedRate(TimerTask task, long delay, long period)
从指定的时间延迟后 ,间隔指定的毫秒数重复的执行(不能执行过去任务,否则会抛出异常,delay不能为负数)
-
void cancel()
终止当前任务
-
日期时间 API
Java 8通过发布新的 API (JSR 310)来进一步加强对日期与时间的处理。在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
-
非线程安全:java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
-
设计差:Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
-
时区处理麻烦:日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:
-
Local
(本地):简化了日期时间的处理,没有时区的问题。 -
Zoned
(时区):通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作
本地化日期时间 API
LocalDate
/LocalTime
和 LocalDateTime
类可以在处理时区不是必须的情况。代码如下:
// 获取当前的日期时间
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("当前时间: " + currentTime);
LocalDate date1 = currentTime.toLocalDate();
System.out.println("date1: " + date1);
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
使用时区的日期时间API
需要考虑到时区,可以使用时区的日期时间API:
// 获取当前时间日期
ZonedDateTime date1 =ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
System.out.println("date1: " + date1);
ZoneId id = ZoneId.of("Europe/Paris");
System.out.println("ZoneId: " + id);
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("当期时区: " + currentZone);
Optional类
Optional
类是一个可以为null
的容器对象。如果值存在则isPresent()
方法会返回true
,调用get()
方法会返回该对象。
Optional
是个容器:它可以保存类型T的值,或者仅仅保存null
。Optional
提供很多有用的方法,这样我们就不用显式进行空值检测。Optional
类的引入很好的解决空指针异常。
常用方法:
方法 | 描述 |
---|---|
Optional.of(T t) |
创建要给Optional实例 |
Optional.empty() |
创建一个空的Optional实例 |
Optional.ofNullable(T t) |
若t不为null,创建Optional实例,否则创建空的实例 |
isPresent() |
判断是否包含值 |
orElse(T t) |
如果调用对象包含值,返回该值,否则返回t |
orElseGet(Supplier s) |
如果调用对象包含值,返回该值,否则返回s获取的值 |
map(function f) |
如果有值对其处理,并发挥处理后的Optional ,否则返回Optional.empty() |
flatMap(Function mapper) |
与map类似,要求返回值必须是Optional |
class Mytest {
public static void main(){
User user = new User();
user.setPassword("admin");
String name = getPwd(user);
}
public static String getPwd(User u){
if(u==null){
return "unknow";
}
return u.getPassword();
}
}
// 改写
public static String getPwd(User u){
return Optional.ofNullable(u).map(user->user.getPassword()).orElse("unknow");
}