Date类是从JDK1.1就开始存在的老类,其提供了针对日期进行操作的诸多方法,但其却一直饱受诟病,不同的起始编号,国际化的低支持,JDK官方也认识到这个问题,后台提出使用Calendar类进行日期操作,日期的格式化交给DateFormat,虽然我们已经不再使用Date类中的大多数方法,但是还有一部分保留的内容指的我们一谈。
Date类之前有6大构造器,其中四个已经标注弃用,我们我不再看他,我们重点看另外两个:
/**
* Allocates a Date
object and initializes it so that
*/
public Date() {
this(System.currentTimeMillis());
}
/**
* @param date the milliseconds since January 1, 1970, 00:00:00 GMT.
*/
public Date(long date) {
fastTime = date;
}
第一个构造器是无参构造器,通过调用System的currentTimeMillis()方法来获取当前时间戳,这个时间戳是从1970年到当前时间的毫秒级数据,第二个构造器,可以将一个毫秒级的数据定义为Date格式的日期。
Date中定义了诸多的日期操作方法,但是大多数都已弃用,只剩余为数不多的几个方法:
/**
* Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
* represented by this Date object.
*/
public long getTime() {
return getTimeImpl();
}
/**
* Sets this Date
object to represent a point in time that is
* time
milliseconds after January 1, 1970 00:00:00 GMT.
*/
public void setTime(long time) {
fastTime = time;
cdate = null;
}
/**
* Tests if this date is before the specified date.
*/
public boolean before(Date when) {
return getMillisOf(this) < getMillisOf(when);
}
/**
* Tests if this date is after the specified date.
*/
public boolean after(Date when) {
return getMillisOf(this) > getMillisOf(when);
}
上面显示的四个方法是Date类中现在还在使用的几个常用方法:
public static void main(String[] args) {
Date now = new Date();//获取当前时间
Date when = new Date(10201020097865L);//根据时间戳定义指定时间点
boolean b1 = now.after(when);
boolean b2 = now.before(when);
Long d1 = now.getTime();
Long d2 = when.getTime();
System.out.println("now值为:"+now);
System.out.println("when值为:"+when);
System.out.println("b1值为:"+b1);
System.out.println("b2值为:"+b2);
System.out.println("d1值为:"+d1);
System.out.println("d2值为:"+d2);
}
结果为:
now值为:Thu Jul 06 13:39:12 CST 2017
when值为:Tue Apr 04 16:41:37 CST 2293
b1值为:false
b2值为:true
d1值为:1499319552116
d2值为:10201020097865
Date类现在并不推荐使用,Java推荐了Calendar和DateFormat,甚至SimpleDateFormat来替代它,Date中仅剩的几个方法仍然还很实用,尤其是before与after方法,可以很方便的判断两个时间点的先后,当然判断的条件是将你的时间转换成Date格式,使用Date剩余的两个构造器实现即可,当然也可以使用推荐的SimpleDateFormat方法进行简单的格式化日期格式字符串的方式得到Date格式的时间点,这些会在稍后了解到!
Java官方推荐使用Calendar来替换Date的使用,Calendar与Date之间可以自由的进行转换,转换的纽带是time,使用Calendar的getTime()方法可以得到一个Date类型的对象,这个对象底层是使用Date的第二个带Long型参数的构造器创建的,这个Long型参数是Calendar中的time字段中保存的值,这个time字段的值是在具体的实现类中定义赋值的比如GregorianCalendar中的实现computeTime(),这个方法的目的就是将field值转换为time值,这个涉及到Calendar中的两种模式,之后会有介绍;而通过Calendar的setTime(Date date)方法可以将一个Date对象转换为一个Calendar对象,这个方法以一个Date对象为参数,底层调用的setTimeInMillis(long millis)方法,将date.getTime()的值作为参数,再底层会将这个Long型参数值赋值给time字段,这时会重计算field值。
Calendar与Date的转换
public static void main(String[] args) {
//Calendar--->Date
Calendar c = Calendar.getInstance();
Date d = c.getTime();
//Date--->Calendar
Date d1 = new Date();
Calendar c1 = Calendar.getInstance();
c1.setTime(d1);
System.out.println(d);
System.out.println(c1.get(Calendar.YEAR)+"年"+(c1.get(Calendar.MONTH)+1)+"月"+c1.get(Calendar.DATE)+"日");
}
结果:
Sat Jul 08 10:39:14 CST 2017
2017年7月8日
Calendar中有两种描述时间内容的域,一种就是time,它用来保存Calendar对象所代表的时间点据1970年1月1日 00:00:00的毫秒数,另一种就是field,它是一个数组,它表示的并不是一个内容,而是Calendar内部定义的最多静态常量字段。
而这一般情况下是同步的,即表述的是同一时间点,但也有可能会出现不同步的情况:
更确切的说,当我们通过Calendar.getInstance()方法获取一个全新的Calendar对象时,它所代表的时间点是通过time来设置的,而这个time的值是通过System.currentTimeMillis()得到的,通过time定义Calendar,isTimeSet为true,表示time值是最新的(真的),areFieldsSet为false,表示field字段的值都是旧的(假的),因为当我们重新设置了time值之后,Calendar所代表的时间点就发生了变化(这里是首次,相当于从无到有,也算是变化,之后当我们为Calendar的time重新设置一个新值时,Calendar的时间点就会再次发生变化,它会指向最新的time值所代表的时间点),而这时field中还表示的是原来的时间点内容,然后会调用computeFields()方法进行所有字段值的重计算,确保field中的值与time同步,并同时将areFieldsSet和areAllFieldsSet设置为true,表示所有的field代表的时间值也是最新的了(真)。其实我们每次更改time值都会自动触发重计算,来确保两个域所描述的时间点一致(即同步),这也就是上面b所述的内容。
但是如果我们通过set(int field, int value)单独对field中的某行一字段进行更改时,首先会触发一个验证,areFieldsSet为真而areAllFieldsSet为false时,表示只有一部分field是最新的情况,即存在部分field属于旧的情况,针对这种情况会触发field的重新计算;之后会将isTimeSet设置为false,areFieldsSet设置为false,将isSet[field]设置为true(将当前field设置为真),这种情况下,当我们使用getTime()获取time值所代表的时间点时,由于isTimeSet为false,会触发time的重计算,这个计算依据是根据field的值进行的,之后将isTimeSet设置为true,同样我们在通过get(int field)获取某个field值时也会先验证isTimeSet是否为true,如果为false,同样会触发time的重计算,然后验证areFieldsSet为false,则触发其余field的重计算。
time的重计算是依据field的,确切的说是依据部分field的,而有一部分field也是在field的基础上再计算的,所以可以说有一部分field是固定的,是和time息息相关的。
以上种种所述全部是Calendar内部的实现规则,对外而言,我们只需要简单的调用即可,所有这些都被隐藏在内部,从而保证我们通过对外方法获取到的直接就是正确的值。
public static void main(String[] args) throws ParseException {
System.out.println("-------初始情况-------");
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DATE));
System.out.println(c.get(Calendar.HOUR));
System.out.println("-------重设置time-------");
c.setTime(new SimpleDateFormat("yyyyMMdd").parse("20170501"));
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DATE));
System.out.println(c.get(Calendar.HOUR));
System.out.println("-------重设置field-------");
c.set(Calendar.MONTH, 4);
System.out.println(c.getTime());
System.out.println(c.get(Calendar.DATE));
System.out.println(c.get(Calendar.HOUR));
System.out.println("总结:time与field所代表时间点同步,所有的不同步全部在内部处理完成");
}
结果:
-------初始情况-------
Sat Jul 08 13:08:34 CST 2017
1
-------重设置time-------
Mon May 01 00:00:00 CST 2017
0
-------重设置field-------
Mon May 01 00:00:00 CST 2017
0
总结:time与field所代表时间点同步,所有的不同步全部在内部处理完成
lenient:该模式下可以自动规则化用户赋值给Calendar的不规则值,比如1月32日会被解析为2月1日
non-lenient:该模式下不会自动解析不规则的输入,而是一旦发现不规则输入,就会报出异常
这也叫Calendar的容错性,lenient的开启与关闭使用setLenient(boolean lenient)方法来设置,true表示开启容错性(默认情况),false表示关闭该功能。
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, 8);
c.set(Calendar.DAY_OF_MONTH, 33);
System.out.println(c.getTime()+"\n");
c.setLenient(false);
c.set(Calendar.MONTH, 8);
c.set(Calendar.DAY_OF_MONTH, 33);
System.out.println(c.getTime());
}
结果:
Tue Oct 03 13:18:48 CST 2017
Exception in thread "main" java.lang.IllegalArgumentException: DAY_OF_MONTH
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2583)
at java.util.Calendar.updateTime(Calendar.java:2606)
at java.util.Calendar.getTimeInMillis(Calendar.java:1118)
at java.util.Calendar.getTime(Calendar.java:1091)
at JdkTest.main(JdkTest.java:87)
从上面的例子中可以看出,默认情况下,我们为Calendar的月份赋值为8即九月份,日期赋值为33即下一月3号,输出为10月3日,容错性将这种不符合规则的输入规则化处理了,而关闭容错性之后,同样的赋值只会报异常java.lang.IllegalArgumentException(非法参数异常)。
public static void main(String[] args) throws ParseException {
//通过SimpleDateFormat解析日期字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hh:mm:ss.SSS");
Date date = sdf.parse("20170502 13:33:23.433");
//将Date格式日期转换成Calendar
Calendar c = Calendar.getInstance();
c.setTime(date);
//获取时间值
System.out.println(c.getTime());
System.out.println("年份为"+c.get(Calendar.YEAR));
System.out.println("月份为"+c.get(Calendar.MONTH));
System.out.println("日期为"+c.get(Calendar.DATE));
System.out.println("日期为"+c.get(Calendar.DAY_OF_MONTH));
System.out.println("日期为"+c.get(Calendar.DAY_OF_WEEK));
System.out.println("日期为"+c.get(Calendar.DAY_OF_WEEK_IN_MONTH));
System.out.println("日期为"+c.get(Calendar.DAY_OF_YEAR));
System.out.println("时为"+c.get(Calendar.HOUR));
System.out.println("时为"+c.get(Calendar.HOUR_OF_DAY));
System.out.println("分为"+c.get(Calendar.MINUTE));
System.out.println("秒为"+c.get(Calendar.SECOND));
System.out.println("毫秒为"+c.get(Calendar.MILLISECOND));
System.out.println("星期为"+c.get(Calendar.WEEK_OF_MONTH));
System.out.println("星期为"+c.get(Calendar.WEEK_OF_YEAR));
System.out.println("历型为"+c.get(Calendar.ERA));
System.out.println("zone为"+c.get(Calendar.ZONE_OFFSET));
//设置
c.set(Calendar.MONTH, Calendar.APRIL);
System.out.println("修改后月份为"+c.get(Calendar.MONTH));
c.set(1999, 0, 23);
System.out.println(c.getTime());
c.set(2000, 1, 12, 13, 33, 14);
System.out.println(c.getTime());
c.set(2001, 2, 13, 14, 13);
System.out.println(c.getTime());
//运算
System.out.println("-----运算-----");
c.add(Calendar.YEAR, 12);
System.out.println(c.getTime());
c.add(Calendar.MONTH, -1);
System.out.println(c.getTime());
c.roll(Calendar.DATE, true);
System.out.println(c.getTime());
c.add(Calendar.DATE, 1);
System.out.println(c.getTime());
//roll与add运算对比
c.set(2000, 1, 29);
System.out.println(c.getTime());
c.roll(Calendar.DATE, 1);
System.out.println(c.getTime());
c.set(2000, 1, 29);
c.add(Calendar.DATE, 1);
System.out.println(c.getTime());
}
结果:
Tue May 02 13:33:23 CST 2017
年份为2017
月份为4
日期为2
日期为2
日期为3
日期为1
日期为122
时为1
时为13
分为33
秒为23
毫秒为433
星期为1
星期为18
历型为1
zone为28800000
修改后月份为3
Sat Jan 23 13:33:23 CST 1999
Sat Feb 12 13:33:14 CST 2000
Tue Mar 13 14:13:14 CST 2001
-----运算-----
Wed Mar 13 14:13:14 CST 2013
Wed Feb 13 14:13:14 CST 2013
Thu Feb 14 14:13:14 CST 2013
Fri Feb 15 14:13:14 CST 2013
Tue Feb 29 14:13:14 CST 2000
Tue Feb 01 14:13:14 CST 2000
Wed Mar 01 14:13:14 CST 2000
对比上面最后的两行输出,可以看出add与roll的运算规则其实是不同的,roll的运算不会影响大规则(这里的大规则指的是月份的改变)的改变,而add会影响。
综上所述,我们可以简单的认识一下Calendar类,并学会简单的使用它,对于其内部实现,还需要认真敲一敲源码。
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。
add(BigDecimal) BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal) BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal) BigDecimal对象中的值相除,然后返回这个对象。
toString() 将BigDecimal对象的数值转换成字符串。
doubleValue() 将BigDecimal对象中的值以双精度数返回。
floatValue() 将BigDecimal对象中的值以单精度数返回。
longValue() 将BigDecimal对象中的值以长整数返回。
intValue() 将BigDecimal对象中的值以整数返回。
4、格式化及例子
由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。
以利用BigDecimal对货币和百分比格式化为例。首先,创建BigDecimal对象,进行BigDecimal的算术运算后,分别建立对货币和百分比格式化的引用,最后利用BigDecimal对象作为format()方法的参数,输出其格式化的货币值和百分比。
public static void main(String[] args) {
NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用
NumberFormat percent = NumberFormat.getPercentInstance(); //建立百分比格式化引用
percent.setMaximumFractionDigits(3); //百分比小数点最多3位
BigDecimal loanAmount = new BigDecimal("15000.48"); //贷款金额
BigDecimal interestRate = new BigDecimal("0.008"); //利率
BigDecimal interest = loanAmount.multiply(interestRate); //相乘
System.out.println("贷款金额:\t" + currency.format(loanAmount));
System.out.println("利率:\t" + percent.format(interestRate));
System.out.println("利息:\t" + currency.format(interest));
}
运行结果如下:
贷款金额: ¥15,000.48
利率: 0.8%
利息: ¥120.00
5、BigDecimal比较
BigDecimal是通过使用compareTo(BigDecimal)来比较的,具体比较情况如下:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("2");
BigDecimal c = new BigDecimal("1");
int result1 = a.compareTo(b);
int result2 = a.compareTo(c);
int result3 = b.compareTo(a);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
打印结果是:-1、0、1,即左边比右边数大,返回1,相等返回0,比右边小返回-1。
注意不能使用equals方法来比较大小。
使用BigDecimal的坏处是性能比double和float差,在处理庞大,复杂的运算时尤为明显,因根据实际需求决定使用哪种类型。
Java提供了一个操作Set、List和Map等集合的工具类:Collections,该工具类提供了大量方法对集合进行排序、查询和修改等操作,还提供了将集合对象置为不可变、对集合对象实现同步控制等方法。
collections提供了如下几个方法用于对List集合元素进行排序:
static void reverse(List list): 反转列表中元素的顺序。
static void shuffle(List list) : 对List集合元素进行随机排序。
static void sort(List list) :根据元素的自然顺序 对指定列表按升序进行排序
static void sort(List list, Comparator c) : 根据指定比较器产生的顺序对指定列表进行排序。
static void swap(List list, int i, int j) :在指定List的指定位置i,j处交换元素。
static void rotate(List list, int distance) :当distance为正数时,将List集合的后distance个元素“整体”移到前面;当distance为负数时,将list集合的前distance个元素“整体”移到后边。该方法不会改变集合的长度。
下面程序简单示范了利用collections工具类来操作List集合:
public class TestSort
{
public static void main(String[] args)
{
ArrayList nums = new ArrayList();
nums.add(2);
nums.add(-5);
nums.add(3);
nums.add(0);
//输出:[2, -5, 3, 0]
System.out.println(nums);
//将List集合元素的次序反转
Collections.reverse(nums);
//输出:[0, 3, -5, 2]
System.out.println(nums);
//将List集合元素的按自然顺序排序
Collections.sort(nums);
//输出:[-5, 0, 2, 3]
System.out.println(nums);
//将List集合元素的按随机顺序排序
Collections.shuffle(nums);
//每次输出的次序不固定
System.out.println(nums);
//后两个整体移动到前边
Collections.rotate(nums,2);
System.out.println(nums);
}
}
输出结果:
[2, -5, 3, 0]
[0, 3, -5, 2]
[-5, 0, 2, 3]
[2, 3, -5, 0]
[-5, 0, 2, 3]
重写sort中的Comparator接口实现自定义排序:
package collections.sort;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
public class TestSort {
public static void main(String[] args) {
List<Book> books = new ArrayList<>();
books.add(new Book(5l, subDate(0), "zjq5"));
books.add(new Book(2l, subDate(3), "zjq2"));
books.add(new Book(3l, subDate(2), "zjq3"));
books.add(new Book(1l, subDate(4), "zjq1"));
books.add(new Book(4l, subDate(1), "zjq4"));
Collections.sort(books, new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
//o1和o2反过来决定升序和降序
// return o1.getId().compareTo(o2.getId());升序
// return o2.getId().compareTo(o1.getId());降序
// return o1.getName().compareTo(o2.getName());
// return o2.getName().compareTo(o1.getName());
// return o1.getTime().compareTo(o2.getTime());
return o2.getTime().compareTo(o1.getTime());
}
});
for (Book book : books) {
System.out.println(book.getId());
}
}
//日期减一天 加一天
public static Date subDate(int sum){
return new Date(new Date().getTime()-sum*24*60*60*1000);
}
}
collections还提供了如下用于查找、替换集合元素的常用方法:
static int binarySearch(List list,Object key):使用二分搜索法搜索指定列表,以获得指定对象在List集合中的索引。
此前必须保证List集合中的元素已经处于有序状态。
static Object max(Collection coll): 根据元素的自然顺序,返回给定collection 的最大元素。
static Object max(Collection coll,Comparator comp): 根据指定比较器产生的顺序,返回给定 collection 的最大元素。
static Object min(Collection coll): 根据元素的自然顺序,返回给定collection 的最小元素。
static Object min(Collection coll,Comparator comp): 根据指定比较器产生的顺序,返回给定 collection 的最小元素。
static void fill(List list, Object obj) : 使用指定元素替换指定列表中的所有元素。
static int frequency(Collection c, Object o) :返回指定 collection 中等于指定对象的出现次数。
static int indexOfSubList(List source, List target) : 返回指定源列表中第一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
static int lastIndexOfSubList(List source, List target) :返回指定源列表中最后一次出现指定目标列表的起始位置;如果没有出现这样的列表,则返回 -1。
static boolean replaceAll(List list, T oldVal, T newVal) :使用一个新值替换List对象的所有旧值oldVal。
下面程序简单示范了Collections工具类的用法:
public class TestSearch
{
public static void main(String[] args)
{
ArrayList nums = new ArrayList();
nums.add(2);
nums.add(-5);
nums.add(3);
nums.add(0);
//输出:[2, -5, 3, 0]
System.out.println(nums);
//输出最大元素,将输出3
System.out.println(Collections.max(nums));
//输出最小元素,将输出-5
System.out.println(Collections.min(nums));
//将nums中的0使用1来代替
Collections.replaceAll(nums , 0 , 1);
//输出:[2, -5, 3, 1]
System.out.println(nums);
//判断-5 在List集合中出现的次数,返回1
System.out.println(Collections.frequency(nums , -5));
//对nums集合排序
Collections.sort(nums);
//输出:[-5, 1, 2, 3]
System.out.println(nums);
//只有排序后的List集合才可用二分法查询,输出3
System.out.println(Collections.binarySearch(nums , 3));
}
}
Collectons提供了多个synchronizedXxx()方法,该方法返回指定集合对象对应的同步对象,从而解决多线程并发访问集合时的线程安全问题。
正如前面介绍的HashSet,TreeSet,arrayList,LinkedList,HashMap,TreeMap都是线程不安全的。Collections提供了多个静态方法可以把他们包装成线程同步的集合。
方法如下:
static Collection synchronizedCollection(Collection c) :返回指定 collection 支持的同步(线程安全的)collection。
static List synchronizedList(List list) :返回指定列表支持的同步(线程安全的)列表。
static Map synchronizedMap(Map m) :返回由指定映射支持的同步(线程安全的)映射。
static Set synchronizedSet(Set s) : 返回指定 set 支持的同步(线程安全的)set。
下面程序示范了创建四个线程同步集合对象:
public class TestSynchronized
{
public static void main(String[] args)
{
//下面程序创建了四个同步的集合对象
Collection c = Collections.synchronizedCollection(new ArrayList());
List list = Collections.synchronizedList(new ArrayList());
Set s = Collections.synchronizedSet(new HashSet());
Map m = Collections.synchronizedMap(new HashMap());
}
}
上面程序中,直接将新创建的集合对象传给了Collections的synchronizedXxx方法,这样就直接获取了List、Set、Map的线程实现版本。
Collections提供了如下三个方法来返回一个不可变集合:
emptyXxx(): 返回一个空的、不可变的集合对象,此处的集合既可以是List,也可以是Set,还可以是Map。
singletonXxx(): 返回一个只包含指定对象(只有一个或一个元素)的不可变的集合对象,此处的集合可以是:List,Set,Map。
unmodifiableXxx(): 返回指定集合对象的不可变视图,此处的集合可以是:List,Set,Map。
通过上面Collections提供的三类方法,可以生成“只读”的Collection或Map,看下面程序:
public class TestUnmodifiable
{
public static void main(String[] args)
{
//创建一个空的、不可改变的List对象
List<String> unmodifiableList = Collections.emptyList();
//unmodifiableList.add("java"); //添加出现异常:java.lang.UnsupportedOperationException
System.out.println(unmodifiableList);// []
//创建一个只有一个元素,且不可改变的Set对象
Set unmodifiableSet = Collections.singleton("Struts2权威指南");//[Struts2权威指南]
System.out.println(unmodifiableSet);
//创建一个普通Map对象
Map scores = new HashMap();
scores.put("语文" , 80);
scores.put("Java" , 82);
//返回普通Map对象对应的不可变版本
Map unmodifiableMap = Collections.unmodifiableMap(scores);
//下面任意一行代码都将引发UnsupportedOperationException异常
unmodifiableList.add("测试元素");
unmodifiableSet.add("测试元素");
unmodifiableMap.put("语文",90);
}
}
注意不要把Collection接口和Collections工具类搞混哦!
Arrays类位于 java.util 包中,主要包含了操纵数组的各种方法。
注意:该方法返回的是Arrays内部静态类ArrayList,而不是我们平常使用的ArrayList,,该静态类ArrayList没有覆盖父类的add, remove等方法,所以如果直接调用,会报UnsupportedOperationException异常
List<Integer> list = Arrays.asList(1, 2, 3);
list.forEach(System.out::println); // 1 2 3
Integer[] data = {1, 2, 3};
List<Integer> list = Arrays.asList(data);
list.forEach(System.out::println); // 1 2 3
int[] data = {1, 2, 3};
List<int[]> list = Arrays.asList(data);
System.out.println(list.size()); // 1
System.out.println(Arrays.toString(list.get(0))); // [1, 2, 3]
Arrays.fill(Object[] array, Object obj)
Integer[] data = {1, 2, 3, 4};
Arrays.fill(data, 9);
System.out.println(Arrays.toString(data)); // [9, 9, 9, 9]
Arrays.fill(Object[] array, int fromIndex, int toIndex, Object obj)
Integer[] data = {1, 2, 3, 4};
Arrays.fill(data, 0, 2, 9);
System.out.println(Arrays.toString(data)); // [9, 9, 3, 4]
Arrays.sort(Object[] array)
String[] data = {"1", "4", "3", "2"};
System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
Arrays.sort(data);
System.out.println(Arrays.toString(data)); // [1, 2, 3, 4]
Arrays.sort(T[] array, Comparator super T> comparator)
String[] data = {"1", "4", "3", "2"};
System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
// 实现降序排序,返回-1放左边,1放右边,0保持不变
Arrays.sort(data, (str1, str2) -> {
if (str1.compareTo(str2) > 0) {
return -1;
} else {
return 1;
}
});
System.out.println(Arrays.toString(data)); // [4, 3, 2, 1]
Arrays.sort(Object[] array, int fromIndex, int toIndex)
String[] data = {"1", "4", "3", "2"};
System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
// 对下标[0, 3)的元素进行排序,即对1,4,3进行排序,2保持不变
Arrays.sort(data, 0, 3);
System.out.println(Arrays.toString(data)); // [1, 3, 4, 2]
Arrays.sort(T[] array, int fromIndex, int toIndex, Comparator super T> c)
String[] data = {"1", "4", "3", "2"};
System.out.println(Arrays.toString(data)); // [1, 4, 3, 2]
// 对下标[0, 3)的元素进行降序排序,即对1,4,3进行降序排序,2保持不变
Arrays.sort(data, 0, 3, (str1, str2) -> {
if (str1.compareTo(str2) > 0) {
return -1;
} else {
return 1;
}
});
System.out.println(Arrays.toString(data)); // [4, 3, 1, 2]
注意:其余重载方法与 sort() 相同
Arrays.parallelSort(T[] array)
String[] data = {"1", "4", "3", "2"};
Arrays.parallelSort(data);
System.out.println(Arrays.toString(data)); // [1, 2, 3, 4]
注意:在调用该方法之前,必须先调用sort()方法进行排序,如果数组没有排序,
那么结果是不确定的,此外如果数组中包含多个指定元素,则无法保证将找到哪个元素。
Arrays.binarySearch(Object[] array, Object key)
这里需要先看下binarySearch()方法的源码,对了解该方法有很大的帮助。
public static int binarySearch(long[] a, long key) {
return binarySearch0(a, 0, a.length, key);
}
private static int binarySearch0(long[] a, int fromIndex, int toIndex, long key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
long midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
从源码中可以看到:
当搜索元素是数组元素,则返回该元素的索引值。
如果不是数组元素,则返回 - (索引值 + 1),具体的用法可以看下面的例子。
Integer[] data = {1, 3, 5, 7};
Arrays.sort(data);
System.out.println(Arrays.binarySearch(data, 1)); // 0
Integer[] data = {1, 3, 5, 7};
Arrays.sort(data);
// 此时程序会把数组看作 {0, 1, 3, 5, 7},此时0的索引值为0,则搜索0时返回 -(0 + 1) = -1
System.out.println(Arrays.binarySearch(data, 0)); // -1
Integer[] data = {1, 3, 5, 7};
Arrays.sort(data);
// 此时程序会把数组看作 {1, 3, 5, 7, 9},此时9的索引值为4,则搜索8时返回 -(4 + 1) = -5
System.out.println(Arrays.binarySearch(data, 8)); // -5
Integer[] data = {1, 3, 5, 7};
Arrays.sort(data);
// 此时程序会把数组看作 {1, 2, 3, 5, 7},此时2的索引值为1,则搜索2时返回 -(1 + 1) = -2
System.out.println(Arrays.binarySearch(data, 2)); // -2
Arrays.binarySearch(Object[] array, int fromIndex, int toIndex, Object obj)
Integer[] data = {1, 3, 5, 7};
Arrays.sort(data);
// {1, 3},3的索引值为1
System.out.println(Arrays.binarySearch(data, 0, 2, 3)); // 1
Arrays.copyOf(T[] original, int newLength)
Integer[] data1 = {1, 2, 3, 4};
Integer[] data2 = Arrays.copyOf(data1, 2);
System.out.println(Arrays.toString(data2)); // [1, 2]
Integer[] data2 = Arrays.copyOf(data1, 5);
System.out.println(Arrays.toString(data2)); // [1, 2, 3, 4, null]
Integer[] data1 = {1, 2, 3, 4};
Integer[] data2 = Arrays.copyOfRange(data1, 0, 2);
System.out.println(Arrays.toString(data2)); // [1, 2]
Integer[] data2 = Arrays.copyOfRange(data1, 0, 5);
System.out.println(Arrays.toString(data2)); // [1, 2, 3, 4, null]
Integer[] data1 = {1, 2, 3};
Integer[] data2 = {1, 2, 3};
System.out.println(Arrays.equals(data1, data2)); // true
Integer[][] data1 = {{1,2,3}, {1,2,3}};
Integer[][] data2 = {{1,2,3}, {1,2,3}};
System.out.println(Arrays.deepEquals(data1, data2)); // true
Integer[] data = {1, 2, 3};
System.out.println(Arrays.hashCode(data)); // 30817
Integer[][] data = {{1, 2, 3}, {1, 2, 3}};
System.out.println(Arrays.deepHashCode(data)); // 987105
Integer[] data = {1, 2, 3};
System.out.println(Arrays.toString(data)); // [1, 2, 3]
返回多维数组元素的字符串形式。
Integer[][] data = {{1, 2, 3}, {1, 2, 3}};
System.out.println(Arrays.deepToString(data)); // [[1, 2, 3], [1, 2, 3]]
Integer[] data = {2, 3, 4, 5};
// 第一个元素2不变,将其与第二个元素3一起作为参数x, y传入,得到乘积6,作为数组新的第二个元素
// 再将6和第三个元素4一起作为参数x, y传入,得到乘积24,作为数组新的第三个元素,以此类推
Arrays.parallelPrefix(data, (x, y) -> x * y);
System.out.println(Arrays.toString(data)); // [2, 6, 24, 120]
Integer[] data = {2, 3, 4, 5};
// 第一个元素2不变,将其与第二个元素3一起作为参数x, y传入,得到乘积6,作为数组新的第二个元素
// 再将6和第三个元素4一起作为参数x, y传入,得到乘积24,作为数组新的第三个元素,以此类推
Arrays.parallelPrefix(data, (x, y) -> x * y);
System.out.println(Arrays.toString(data)); // [2, 6, 24, 120]
public class Students {
private String name;
private Integer age;
public Students(String name, Integer age) {
this.name = name;
this.age = age;
}
// 省略get、set方法
}
public static void main(String[] args) {
Students[] data = new Students[5];
IntStream.range(0,5).forEach(i -> data[i] = new Students("小明"+i+"号", i));
// 返回分片迭代器
Spliterator<Students> spliterator = Arrays.spliterator(data);
spliterator.forEachRemaining(stu -> {
System.out.println("学生姓名: " + stu.getName() + " " + "学生年龄: " + stu.getAge());
// 学生姓名: 小明0号 学生年龄: 0
// 学生姓名: 小明1号 学生年龄: 1
// 学生姓名: 小明2号 学生年龄: 2
// 学生姓名: 小明3号 学生年龄: 3
// 学生姓名: 小明4号 学生年龄: 4
});
}
Integer[] data = {1, 2, 3, 4};
List<Integer> list = Arrays.stream(data).collect(toList());
System.out.println(list); // [1, 2, 3, 4]
closeQuietly:关闭一个IO流、socket、或者selector且不抛出异常,通常放在finally块。
toString:转换IO流、 Uri、 byte[]为String。
copy:IO流数据复制,从输入流写到输出流中,最大支持2GB。
toByteArray:从输入流、URI获取byte[]。
write:把字节. 字符等写入输出流。
toInputStream:把字符转换为输入流。
readLines:从输入流中读取多行数据,返回List<String>。
copyLarge:同copy,支持2GB以上数据的复制。
lineIterator:从输入流返回一个迭代器,根据参数要求读取的数据量,全部读取,如果数据不够,则失败。
deleteDirectory:删除文件夹。
readFileToString:以字符形式读取文件内容。
deleteQueitly:删除文件或文件夹且不会抛出异常。
copyFile:复制文件。
writeStringToFile:把字符写到目标文件,如果文件不存在,则创建。
forceMkdir:强制创建文件夹,如果该文件夹父级目录不存在,则创建父级。
write:把字符写到指定文件中。
listFiles:列举某个目录下的文件(根据过滤器)。
copyDirectory:复制文件夹。
forceDelete:强制删除文件。
isBlank:字符串是否为空 (trim后判断)
isEmpty:字符串是否为空 (不trim并判断)
equals:字符串是否相等
join:合并数组为单一字符串,可传分隔符
split:分割字符串
EMPTY:返回空字符串
trimToNull:trim后为空字符串则转换为null
replace:替换字符串
toString:把Entity转换为字符串
consume:确保Entity中的内容全部被消费。可以看到源码里又一次消费了Entity的内容,假如用户没有消费,那调用Entity时候将会把它消费掉
toByteArray:把Entity转换为字节流
consumeQuietly:和consume一样,但不抛异常
getContentCharset:获取内容的编码
isBlank:字符串是否为空 (trim后判断)
isEmpty:字符串是否为空 (不trim并判断)
equals:字符串是否相等
join:合并数组为单一字符串,可传分隔符
split:分割字符串
EMPTY:返回空字符串
replace:替换字符串
capitalize:首字符大写
getExtension:返回文件后缀名
getBaseName:返回文件名,不包含后缀名
getName:返回文件全名
concat:按命令行风格组合文件路径(详见方法注释)
removeExtension:删除后缀名
normalize:使路径正常化
wildcardMatch:匹配通配符
seperatorToUnix:路径分隔符改成unix系统格式的,即/
getFullPath:获取文件路径,不包括文件名
isExtension:检查文件后缀名是不是传入参数(List<String>)中的一个
hasText:检查字符串中是否包含文本
hasLength:检测字符串是否长度大于0
isEmpty:检测字符串是否为空(若传入为对象,则判断对象是否为null)
commaDelimitedStringToArray:逗号分隔的String转换为数组
collectionToDelimitedString:把集合转为CSV格式字符串
replace 替换字符串
delimitedListToStringArray:相当于split
uncapitalize:首字母小写
collectionToDelimitedCommaString:把集合转为CSV格式字符串
tokenizeToStringArray:和split基本一样,但能自动去掉空白的单词
contains:是否包含某字符串
addAll:添加整个数组
clone:克隆一个数组
isEmpty:是否空数组
add:向数组添加元素
subarray:截取数组
indexOf:查找某个元素的下标
isEquals:比较数组是否相等
toObject:基础类型数据数组转换为对应的Object数组
参考十五:org.apache.commons.lang3.StringEscapeUtils
format:格式化参数,返回一个HTTP POST或者HTTP PUT可用application/x-www-form-urlencoded字符串
parse:把String或者URI等转换为List<NameValuePair>
md5Hex:MD5加密,返回32位字符串
sha1Hex:SHA-1加密
sha256Hex:SHA-256加密
sha512Hex:SHA-512加密
md5:MD5加密,返回16位字符串
isEmpty:是否为空
select:根据条件筛选集合元素
transform:根据指定方法处理集合元素,类似List的map()
filter:过滤元素,雷瑟List的filter()
find:基本和select一样
collect:和transform 差不多一样,但是返回新数组
forAllDo:调用每个元素的指定方法
isEqualCollection:判断两个集合是否一致
contains:是否包含某个字符串
addAll:添加整个数组
clone:克隆一个数组
isEmpty:是否空数组
add:向数组添加元素
subarray:截取数组
indexOf:查找某个元素的下标
isEquals:比较数组是否相等
toObject:基础类型数据数组转换为对应的Object数组
getProperty:获取对象属性值
setProperty:设置对象属性值
getPropertyDiscriptor:获取属性描述器
isReadable:检查属性是否可访问
copyProperties:复制属性值,从一个对象到另一个对象
getPropertyDiscriptors:获取所有属性描述器
isWriteable:检查属性是否可写
getPropertyType:获取对象属性类型
unescapeHtml4:转义html
escapeHtml4:反转义html
escapeXml:转义xml
unescapeXml:反转义xml
escapeJava:转义unicode编码
escapeEcmaScript:转义EcmaScript字符
unescapeJava:反转义unicode编码
escapeJson:转义json字符
escapeXml10:转义Xml10
这个现在已经废弃了,建议使用commons-text包里面的方法。
copyPeoperties:复制属性值,从一个对象到另一个对象
getProperty:获取对象属性值
setProperty:设置对象属性值
populate:根据Map给属性复制
copyPeoperty:复制单个值,从一个对象到另一个对象
cloneBean:克隆bean实例