Java8 新增日期处理类
LocalDate
LocalDate类用于表示一个标准格式日期,通常以yyyy-MM-dd格式显示(如:2020-07-07)
LocalDate的使用方法:
//获取当前系统时间所表示的日期对象
LocalDate date = LocalDate.now();
//获取年份
System.out.println(datetime.getYear());
//获取月
System.out.println(date.getMonthValue());//获取月份的整数值1-12
System.out.println(date.getMonth());//获取月份枚举(列举)值
//获取日
System.out.println(date.getDayOfYear());
System.out.println(date.getDayOfMonth());
System.out.println(date.getDayOfWeek());
System.out.println(date.getDayOfWeek().getValue());
//根据指定的日期构建一个LocalDate对象
LocalDate date2 = LocalDate.of(2020,7,8);
LocalTime
LocalTime类用于表示一个标准格式时间,通常以HH:mm:ss.SSS格式显示(如:11:22:33.354)
LocalTime的使用方法:
LocalTime time = LocalTime.now();
//获取时
System.out.println(time.getHour());
//获取分
System.out.println(time.getMinute());
//获取秒
System.out.println(time.getSecond());
//获取毫秒
System.out.println(time.toInstant(ZoneOffset.of("+8")).toEpochMilli());
//根据指定的日期构建一个LocalTime对象
LocalTime time = LocalDate.of(12,11,18);
LocalDateTime
LocalDateTime类用于表示一个标准日期时间格式,通常以yyyy-MM-ddTHH:mm:ss.SSS格式显示(如:2020-08-07T18:18:18)
LocalDateTime的使用方法:
LocalDateTime time = LocalDateTime.now();
//将LocalDateTime 转换为 LocalDate
LocalDate localDate = time.toLocalDate();
LocalTime localTime = time.toLocalTime();
System.out.println(localDate);
System.out.println(localTime);
//根据指定的日期构建一个LocalDateTime对象
LocalDateTime time = LocalDateTime.of(2020,8,9,19,22,12);
DateTimeFormatter
DateTimeFormatter是jdk8新增java.time包中的一个用于对LocalDate,LocalTime,LocalDateTime进行格式化和解析的解析类。
提供一些内置的格式化方式,比如:
1.BASIC_ISO_DATE
2.ISO_DATE
3.ISO_INSTANT
4.ISO_LOCAL_DATE
同时该类还支持自定义的格式化匹配模式,通过以下方法获得:
//获取系统时间:2020-07-08T09:47:37.862
LocalDateTime datetime = LocalDateTime.now();
//需要将以上类型的日期时间转换为自定义格式的字符串
//创建一个格式化解析对象
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
//需要使用以上格式对日期时间格式化包含两种方式
//方法1:
String time = fmt.format(datetime);
//方法2:
String time2 = datetime.format(fmt);
//以上两种方式获取的字符串日期格式一致的,均为:
//2020年07月08日 09时47分37秒
String t = "2020年07月08日 09时33分21秒"; // String --> LocalDateTime
//将String类型日期时间解析为LocalDateTime对象
dateTime = LocalDateTime.parse(t, fmt);
System.out.println(dateTime);
System.out.println(LocalDate.parse("20200708101211",DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
// System.out.println(LocalDate.parse("20200708",DateTimeFormatter.BASIC_ISO_DATE));
泛型
泛型即参数化类型,在JDK1.5之后引入了泛型的概念,参数化类型即将一种数据类型以参数形式传递到类,接口或者方法中,可以将对于数据类型的检查从运行期间提前到编译期。
java中的泛型使用分为三种情况:
- 泛型类
- 泛型接口
- 泛型方法
泛型类
在类声明时在后面通过<>
符号指定类型参数,然后在类中可以使用这些类型参数设置动态类型。
public class MyCalc<I,D,F> {
public I add1(I i1,I i2) {
return null;
}
public D add2(D d1,D d2) {
return null;
}
public F add3(F f1,F f2) {
return null;
}
public static void main(String[] args) {
//创建对象时指定数据类型
MyCalc<Integer,Double,Float> mc = new MyCalc<>();
//方法调用时需要根据前面确定好的类型传入对应类型的参数
mc.add1(10, 20);
mc.add2(3.4, 4.5);
mc.add3(1.22f, 2.22f);
}
}
泛型接口
在声明接口是设置参数化类型,在实现类对接口实现时动态指定数据类型,从而将数据类型在编译期间提前确定,减少在运行期间的数据类型转换操作。
public interface BaseManager<T> {
boolean add(T obj);
boolean delete(T obj);
boolean update(T obj);
T findById(int id);
ArrayList<T> findAll();
}
对应得实现
public class EmpManager implements BaseManager<Emp>{
@Override
public boolean add(Emp obj) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean delete(Emp obj) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean update(Emp obj) {
// TODO Auto-generated method stub
return false;
}
@Override
public Emp findById(int id) {
// TODO Auto-generated method stub
return null;
}
@Override
public ArrayList<Emp> findAll() {
// TODO Auto-generated method stub
return null;
}
}
泛型方法
泛型方法即在声明方法的时候可以设定参数化类型,然后使得可以通过方法传递任意类型的参数,以及返回任意类型的返回值。
public class MethodDemo {
/**
* 泛型方法
* @param <T>
* @param s
* @return
*/
public <T> T query(Class<T> t,String s) {
return null;
}
public static void main(String[] args) {
MethodDemo md = new MethodDemo();
Emp emp = md.query(Emp.class, "");
Dept dept = md.query(Dept.class, "");
String s = md.query(String.class, "");
}
}
上下边界限定:super&extends
//上界限定:只能取值不能存值(只出不进)
ArrayList<? extends Number> list3 = list2;
// list3.add(10);//编译报错
Number n = list3.get(0);
System.out.println(n);
//下届限定:只能存值不能取值(只进不出)
ArrayList<? super Number> list4 = new ArrayList<>();
list4.add(new Integer(10));
list4.add(new Double(3.4));
Object obj = list4.get(0);
集合框架入门
Collection接口
Collection是java集合框架中的顶层接口,用于表示一些相同类型的数据集合,内部提供了一系列用于对集合中元素进行存储的方法。
Collection接口的常见方法:
- addAll(Collection<? extends E> c) 添加一个集合到当前集合中
- clear() 从集合中删除所有的元素
- contains(Object obj) 判断集合中是否包含指定的元素
- isEmpty() 判断集合是否为空
- remove(Object o) 删除指定的元素
- removeAll(Collection<?> c) 删除指定的集合
- size() 获取集合中元素的个数
- toArray() 将集合中的所有元素转换为数组
- iterator() 返回集合中的元素的迭代器
List 接口
List是从Collection继承过来,也是一个接口;List是一个有序集合:内部的元素存储可以按照规定的顺序存储(默认顺序从头到尾依次存储,存储顺序跟添加顺序一致),可以通过索引获取指定位置的元素;
List扩展自Collection,在Collection基础上新增了一些方法
- get(int index) 根据索引获取元素
- set(int index,E e) 向指定的位置插入元素
- remove(int index) 删除指定索引处的元素
- listIterator() 获取一个列表迭代器(有序)
List<String> list = new ArrayList<String>();
list.add("jack");
list.add("rose");
String s = list.get(0);
System.out.println(s);
List<String> list2 = new ArrayList<String>();
list2.add("灾难始终慢我一步");
list2.add("德玛西亚");
//将一个集合作为参数添加到另一个集合中
list2.addAll(list);
System.out.println(list2);
System.out.println(list2.contains(new String("jack")));
Dog d1 = new Dog("1","哮天犬");
Dog d2 = new Dog("2","来福");
Dog d3 = new Dog("3","旺财");
List<Dog> dogs = new ArrayList<>();
dogs.add(d1);
dogs.add(d2);
dogs.add(d3);
Dog d4 = new Dog("2","来福");
System.out.println(d2.equals(d4));
//判断指定对象是否存在容器中(依据类中的equals和hashcode)
System.out.println(dogs.contains(d4));
System.out.println("------------");
dogs.forEach(d->System.out.println(d.getId()+"---"+d.getName()));
//返回指定元素在容器中第一次出现的位置
System.out.println(list.indexOf("jack"));
//获取当前集合对象的迭代器
Iterator<String> it= list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("30")) {
it.remove();
}
System.out.println(s);
}
System.out.println(list);
//获取集合的列表迭代器
ListIterator<String> li = list.listIterator();
while (li.hasNext()) {
String i = li.next();
System.out.println(i);
}
System.out.println("---------");
//从下往上迭代
while(li.hasPrevious()) {
String i =li.previous();
if (i.equals("20")) {
// li.add("30");//添加元素到当前迭代元素的后面
li.set("30");//替换当前迭代到的元素
}
System.out.println(i);
}
System.out.println(list);
list.set(3, "100");
System.out.println(list);
//集合截取 前包后不包
List<String> sub = list.subList(0, 5);
System.out.println(sub);
由于List是一个接口,所以没法直接实例化,因此JDK中提供了一些对于List接口实现的实现类:
- ArrayList
- LinkedList
ArrayList
ArrayList是基于对象数组的实现,初始容量为10(不是new出来就是10,在第一次执行add方法时初始),当容量超出时,会扩容为原来的1.5倍;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容为原来大小1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList
LinkedList是基于链表的List实现,元素之间通过首尾指针连接,在进行修改(增加,删除)时只需要修改元素的首尾指针即可,修改效率要比ArrayList高,但是在查询时,由于LinkedList没有像ArrayList的索引,在查询时需要从链表的第一个元素开始依次向搜索,所以查询效率较低。
ArrayList,LinkedList,Vector区别:
ArrayList和LinkedList区别 :
ArrayList查快改慢;LinkedList改快查慢。
- ArrayList是基于对象数组的实现,内部通过数组拷贝实现扩容;LinkedList是基于链表的实现,同时实现的队列(双端队列);
- ArrayList由于基于数组实现,因此在搜索元素时可直接通过索引快速定位到元素位置,查询效率较高;LinkedList由于基于链表实现,在查询时需要从链表头开始依次查找,查询效率较低。
- 由于数组的长度一旦定义则无法修改,因此在进行非末端更新(插入和删除)时,由于可能涉及到数组拷贝问题,因此修改效率较低;LinkedList在进行元素更新操作时,只需要修改元素首尾指针的指向即可,更新效率较高。
- 两者都是线程不同步的实现。
ArrayList和Vector的区别: - Vector是老式的集合实现,内部基于对象数组实现;ArrayList是jdk1.2新增的集合实现;
- Vector容量扩充时,扩充原来容量2倍;ArrayList扩充为原来的1.5倍;
- Vector是基于线程安全的实现(方法都使用synchronized修饰);ArrayList是非线程安全的实现。
迭代器(Iterator)
迭代器即游标,将集合处理为类似栈结构的数据结构,通过栈顶指针依次向下搜索元素,直到达到栈底为止。
List<String> list = new ArrayList<>();
list.add("10");
list.add("20");
list.add("30");
list.add("40");
list.add("50");
list.add("60");
list.add("70");
list.add("80");
list.add("90");
list.add("100");
//forEach循环实现原理即迭代器
for (String s : list) {
System.out.println(s);
}
//获取当前集合对象的迭代器(游标)
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String s = it.next();
if(s.equals("30")) {
it.remove();
}
System.out.println(s);
}
Java对元素的排序提供了两个用于实现集合排序的接口:
- java.util.Comparator
- java.lang.Comparable
通过对以上接口的实现结合集合中提供的相关方法即可完成排序操作。
Comparator
通过对该接口实现可以完成个性化排序的需求,只需要实现接口中compare方法,根据该方法的返回值决定元素的排序顺序,具体使用如下:
public class MyComparator implements Comparator<String>{
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
}
public class ListDemo4 {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("clack");
names.add("kobe");
names.add("tom");
names.add("wade");
names.add("james");
names.add("allen");
//调用集合类中提供的sort方法(jdk8)
names.sort(new MyComparator());
System.out.println(names);
}
}
运行结果:
[allen, clack, james, kobe, tom, wade]
Comparable
针对需要实现排序的类型对该接口实现之后,并实现内部的compareTo方法可以自定义排序规则,最后通过Collections提供sort方法将需要排序的集合(List)传入即可。
具体使用方式:
1.声明需要具备排序能力实体类,实现Comparable接口:
/**
* 实现Comparable接口后可以使用Collections.sort()实现自然排序
*/
public class Student implements Comparable<Student>{
private int sno;
private String name;
private int age;
private String clz;
public Student(int sno, String name, int age, String clz) {
super();
this.sno = sno;
this.name = name;
this.age = age;
this.clz = clz;
}
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
}
/**
* 实现比较规则
*/
@Override
public int compareTo(Student s) {
//根据年龄排序
return this.age - s.age;
}
@Override
public String toString() {
return "Student [sno=" + sno + ", name=" + name + ", age=" + age + ", clz=" + clz + "]";
}
}
2.实现排序
public class TestStudent {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(1,"kobe",44,"1班"));
list.add(new Student(4,"wade",22,"5班"));
list.add(new Student(10,"jeffry",35,"3班"));
list.add(new Student(9,"tom",21,"2班"));
list.add(new Student(3,"curry",33,"1班"));
list.add(new Student(2,"allen",40,"2班"));
list.add(new Student(5,"grant",19,"5班"));
//集合中的元素对应类型必须实现Comparable接口
Collections.sort(list); // Arrays.sort(arr)
list.forEach(s->System.out.println(s));
}
}
3.执行结果:
Student [sno=5, name=grant, age=19, clz=5班]
Student [sno=9, name=tom, age=21, clz=2班]
Student [sno=4, name=wade, age=22, clz=5班]
Student [sno=3, name=curry, age=33, clz=1班]
Student [sno=10, name=jeffry, age=35, clz=3班]
Student [sno=2, name=allen, age=40, clz=2班]
Student [sno=1, name=kobe, age=44, clz=1班]
Collections类
Collections来自于java.util包中的一个实体类,一般用作于对集合进行常规处理,比如排序,查找,交换,集合生成,转换等;
Collections接口只提供了静态方法,常见的Collections方法:
public class CollectionsDemo {
// 二叉树:红黑树,b+树,avl树
// 20 45 3 7 6 9 22
// 3 6 7 9 20 22 45
// 6
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//向指定的集合(Collection)中添加元素(动态数组)
Collections.addAll(list, "hello","rundy","softeem","world");
System.out.println(list);
//从一组有序的集合中搜索目标元素的所在位置
int i = Collections.binarySearch(list, "softeem");
System.out.println(i);
// List list2 = Collections.emptyList();
//获取集合中的最大值(按自然排序规则)
String max = Collections.max(list);
System.out.println(max);
//根据提供的排序规则从集合中需要匹配规则的最大值
max = Collections.max(list,(s1,s2)->s1.length()-s2.length());
System.out.println(max);
//反转集合
Collections.reverse(list);
System.out.println(list);
//将集合中元素打乱顺序
Collections.shuffle(list);
System.out.println(list);
//将集合中的元素按照提供的排序比较器进行排序
Collections.sort(list, (s1,s2)->s1.compareTo(s2));
//将当前非线程安全的集合转换为线程安全的实现
list = Collections.synchronizedList(list);
System.out.println(list);
}
}
Set
Set集合也是从Collection扩展而来的子集合,相比List集合来说,Set集合内部存储的数据不是按照添加顺序存储,内部不允许出现重复的元素(不允许出现e1.equals(e2)),对null也只允许出现一个,对于set集合常用的实现主要有以下:
- HashSet
- TreeSet
- LinkedHashSet
HashSet
HashSet是针对于Set集合的实现,内部基于HashMap的实现,在进行元素存储时,会对每一个存储的元素进行hash(),获取一个哈希地址,通过该hash地址可以找到对象在内存的位置,因此存储方式跟具体得出的hash值有关系,因此存储顺序可能会跟添加顺序不一致。
public class SetDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("helloworld");
list.add("rose");
list.add("helloworld");
list.add("rose");
System.out.println(list);
Set<String> set = new HashSet<String>();
set.add("admin");
set.add("hello");
set.add("lily");
set.add("admin");
System.out.println(set);
Set<User> users = new HashSet<User>();
users.add(new User(1, "admin"));
users.add(new User(2, "softeem"));
users.add(new User(1, "admin"));
System.out.println(users);
//语法糖
for(String s:set) {
System.out.println(s);
// if(s.equals("lily")) {
// set.remove(s);
// }
}
//获取set集合的迭代器
Iterator<String> it = set.iterator();
while(it.hasNext()) {
String s = it.next();
System.out.println(s);
if(s.equals("lily")) {
//对集合迭代时需要删除元素只能通过迭代器自生的remove方法
//否则就会出现ConcurrentModificationException
it.remove();
}
}
System.out.println(set);
//根据提供的Collection对象构建一个HashSet
Set<String> set2 = new HashSet<>(list);
System.out.println(set2);
}
}
TreeSet
TreeSet集合是基于TreeMap的Set集合实现,内部元素的存储根据元素的自然顺序(存储的元素需要实现Comparable接口)排序;由于元素是自然顺序排序的实现,因此需要保证集合内部存储的元素必须都是相同的数据类型。
public class TreeSetDemo {
public static void main(String[] args) {
Set set = new TreeSet();
set.add("hello");
// set.add(100); //程序执行到这一步时会出现ClassCastException
set.add(true);
/*
* TreeSet使用注意事项:
* 1.内部存储的元素必须是相同的数据类型
* 2.元素对应的数据类型应该实现过Comparable接口
*/
Set<User> users = new TreeSet<>();
users.add(new User(3, "rundy"));
users.add(new User(1, "admin"));
users.add(new User(2, "softeem"));
System.out.println(users);
}
}
对于以上的集合Set<User> users = new TreeSet<>();
集合内部存储的都是User类型数据,并且User类需要实现java.lang.Comparable
接口,TreeSet依据此排序实现对元素的存储进行排序;如果多个元素排序结果一致,则TreeSet会去除重复元素,
例如:
public class User implements Comparable<User>{
private int id;
private String name;
public User(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
@Override
public int compareTo(User u) {
return this.id-u.id;
}
}
当多个用户的id一致时,TreeSet会根据compareTo方法判定元素为重复,此时会去除重复:
Set<User> users = new TreeSet<>();
users.add(new User(3, "rundy"));
users.add(new User(1, "admin"));
users.add(new User(1, "softeem"));
System.out.println(users);
//运行结果
[User [id=1, name=admin], User [id=3, name=rundy]]
使用Compartor
如果被添加到TreeSet中的元素没有实现Comparable接口也可以,此时只需要在创建TreeSet时通过以下构造器,传入排序比较器对象即可:
TreeSet(Comparator<? super E> c)
//User无需实现Comparable接口
//构造TreeSet时传入排序比较器
Set<User> set = new TreeSet<>((u1,u2)->u1.getId()-u2.getId());
set.add(new User(3, "rundy"));
set.add(new User(1, "admin"));
set.add(new User(2, "softeem"));
System.out.println(set);
注意:
- 由于Set集合存储元素的”无序“(不按照添加顺序存储),因此元素没有索引的概念,在获取元素的时候只能通过迭代器迭代。
- HashSet和TreeSet区别
- HashSet是基于哈希表的实现,元素的存储顺序也是按照哈希地址排序,因此是否重复由哈希值确定
- TreeSet是基于二叉树-红黑树实现,元素的存储顺序根据元素实现的Comparable接口中的comparaTo方法的实现排序,是否重复也是根据排序值判定
- TreeSet使用要求:
- 集合中元素必须是同一种数据类型
- 要么让内部元素实现Comparable接口,要么创建TreeSet时提供排序比较器(Comparator)。
List集合和Set集合区别
List集合是一有序的集合,内部元素存储顺序跟添加的一致,List集合允许重复元素;Set反之;
Map(映射)
Map也称之为映射,内部的元素是以键值对为结构存储,可以通过key获取map中的value;Key不允许重复,但是值是可以重复的;
Map集合有一些常见的实现:
- HashMap
- TreeMap
- ConcurrentHashMap
HashMap
HashMap是Map集合一个实现,内部是基于哈希表的排序实现元素存储的,实现原理是链表+数组(JDK8之后引入红黑树)
public class HashMapDemo {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("d", "davied");
map.put("a", "allen");
map.put("c", "allen");
map.put("b", "bob");
System.out.println(map);
Map<String, Object> user = new HashMap<>();
user.put("id", 10);
user.put("name", "狗蛋");
user.put("birth", LocalDate.of(1999, 11, 11));
System.out.println(user);
// 根据键获取值
Object name = user.get("name");
System.out.println(name);
// 如何遍历Map集合
// 获取Map集合键值对的Set集合(Map转换成Set)
// Set<Map.Entry<String, Object>> set = user.entrySet();
// for (Entry<String, Object> e : set) {
// System.out.println(e.getKey()+"-----"+e.getValue());
// }
// 获取map集合的键集
Set<String> keys = user.keySet();
for (String k : keys) {
// 根据键获取值
Object v = user.get(k);
System.out.println(k + "/" + v);
}
//移除指定键对应的元素
user.remove("id");
//修改指定键对应的值
user.replace("name", "隔壁老王");
System.out.println(user);
//获取集合中元素的个数
System.out.println(user.size());
}
}
TreeMap
Treemap的实现是基于二叉排序树中的红黑树实现,所存储的元素要求键必须是同一种数据类型,并且有实现过Comparable接口(或者创建TreeMap时指定排序比较器)
public class TreeMapDemo {
public static void main(String[] args) {
Map<Object, Object> map = new TreeMap<>();
map.put("v", "vaen");
map.put("a", 3.14);
map.put("n", "true");
map.put(new String("cc"), 'c');
System.out.println(map);
Map<Stu, Object> map2 = new TreeMap<Stu, Object>(new Comparator<Stu>{
public int compara(Stu s1,Stu s2){
return s1.getAge() - s2.getAge();
}
});
map2.put(new Stu(10,"孙悟空"), 18000);
map2.put(new Stu(15,"猪八戒"), 28000);
map2.put(new Stu(8,"唐僧"), true);
System.out.println(map2);
}
}
HashMap、Hashtable、TreeMap的区别
- HashMap是基于hash算法的实现,内不通过数组结合链表实现,允许空键值存在,是线程不同步的实现
- TreeMap是基于红黑树的实现,内部元素的存储顺序是由自然顺序对键进行排序之后存储,是线程不同步的实现
- Hashtable是从老式的Dictionary类继承而来,内部的实现原理跟HashMap一样,不允许空键值存在,实现线程同步的实现,运行效率较低