这里写目录标题
前言
本文记录了java第五周的学习,内容包括date的三代日期,list和map,以及io的开头
一、Date类
一共有三代日期
1丶第一代日期类
1.获取当前时间
代码如下
//第一代日期
Date d1=new Date();//获取当前系统时间,精确到秒
System.out.println(d1);
输出的时候输出的是国外的时间格式
Wed Jun 01 08:29:03 CST 2022
进程已结束,退出代码0
2.日期格式转换
正因为输出的时候输出的是国外的时间格式,我们看起来不方便,所以用到了日期格转换
//第一代日期
Date d1=new Date();//获取当前系统时间,精确到秒
System.out.println(d1);
//日期格式转换
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");//创建格式,格式里面的字母不是乱写的
String s1=sdf.format(d1);//使用字符串接受按照创建好的格式输出的对象
System.out.println(s1);
输出对比如下:
Wed Jun 01 08:36:16 CST 2022
2022年06月01日 08:36:16 星期三
进程已结束,退出代码0
也可以把一个格式化的字符串转化为原来的格式,代码如下:
//日期格式转换
SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");//创建格式
String s1=sdf.format(d1);//使用字符串接受按照创建好的格式输出的对象
System.out.println(s1);
//把上述转化好的字符串转化回去
Date parse=sdf.parse(s1);
System.out.println(parse);
输出结果
2022年06月01日 08:42:04 星期三
Wed Jun 01 08:42:04 CST 2022
转化成功
2丶Calendar第二代日期类
主要用它可以方便的进行日期的计算
1.创建
这个类是一个抽象类,我们无法直接建立他的对象,建立的时候用到了getInstance方法,代码如下
Calendar calendar = Calendar.getInstance();//默认是当前日期
2.set创建一个指定日期的Calendar对象
//set创建一个指定日期的Calendar对象
calendar.set(2022, 5, 9);//这里的month写的是五月,实际上显示出来是6月
System.out.println(calendar.getTime());//Thu Jun 09 09:11:21 CST 2022
上面是以下设置三个,年月日,我们也可以利用字段单独设置年月日
比如代码如下
calendar.set(Calendar.YEAR,2021);
calendar.set(Calendar.MONTH,11);
calendar.set(Calendar.DAY_OF_MONTH,6);
3.使用get获取时间
代码如下
Calendar calendar = Calendar.getInstance();//默认是当前日期
//set创建一个指定日期的Calendar对象
calendar.set(2022, 5, 9);//这里的month写的是五月,实际上显示出来是6月
System.out.println(calendar.getTime());//Thu Jun 09 09:11:21 CST 2022
System.out.println(calendar.get(Calendar.YEAR));//2022
System.out.println(calendar.get(Calendar.MONTH));//5
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//9
注意, Calendar没有专门的格式化方法,所以需要我们自己去组合,某种意义上更方便了.
4.Date和Calendar互相转换
- Date转Calendar
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
2.Calendar转Date
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,2021);
calendar.set(Calendar.MONTH,11);
calendar.set(Calendar.DAY_OF_MONTH,6);
calendar.add(Calendar.DAY_OF_MONTH,2);
Date time = calendar.getTime();
3丶第三代日期类
这个类是jdk8以后才有的
1.创建
代码如下
//创建第三代日期
LocalDateTime ldt=LocalDateTime.now();
System.out.println(ldt);
2.格式化
//创建第三代日期
LocalDateTime localDateTime=LocalDateTime.now();
System.out.println(localDateTime);
//2.使用DateTimeFormatter对象来进行格式化
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dtf.format(localDateTime);
System.out.println("格式化的日期:" + format);
输出结果
2022-06-01T09:40:29.896
格式化的日期:2022-06-01 09:40:29
3.get获取具体内容
//创建第三代日期
LocalDateTime localDateTime=LocalDateTime.now();
System.out.println(localDateTime);
//2.使用DateTimeFormatter对象来进行格式化
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dtf.format(localDateTime);
System.out.println("格式化的日期:" + format);
System.out.println("年=" + localDateTime.getYear());
System.out.println("月=" + localDateTime.getMonth());//英文版
System.out.println("月=" + localDateTime.getMonthValue());//中文版
System.out.println("日=" + localDateTime.getDayOfMonth());
System.out.println("时=" + localDateTime.getHour());
System.out.println("分=" + localDateTime.getMinute());
System.out.println("秒=" + localDateTime.getSecond());
运行结果
2022-06-01T09:42:27.703
格式化的日期:2022-06-01 09:42:27
年=2022
月=JUNE
月=6
日=1
时=9
分=42
秒=27
进程已结束,退出代码0
4.plus和minus方法
第三代日期提供了plus和minus方法可以对当前时间进行加或减
代码如下
//看看666天后,是什么时候
LocalDateTime localDateTime1 = localDateTime.plusDays(666);
System.out.println("666天后:" + dtf.format(localDateTime1));
LocalDateTime localDateTime2 = localDateTime.minusMinutes(2022);
System.out.println("2022分钟前 日期为:" + dtf.format(localDateTime2));
运行结果
666天后:2024-03-28 09:46:24
2022分钟前 日期为:2022-05-31 00:04:24
以上就是三代日期的学习总结
二、集合
1丶集合的优势
我认为集合是数组的升级版,相比于数组有许多优势;
1:可以动态保存任意多个对象,比较方便
2:提供了一系列方便的操作对象的方法(add,remove等);
3:使用集合添加删除元素的代码很简洁;
2丶集合框架体系图
这里我从韩顺平老师视频里面截了两张关系图放在这里。
集合主要分为双列集合和单列集合
先放双列集合的图,如下
再放单列集合的关系图,如下
下面我具体展开说一下;
3丶collection接口
单列集合,我们知道接口就是一种规范,他的两个子类list和set实现了他的规范。来看一下他的两个子类的区别
List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
来看一下具体区别!
List接口
List是元素有序并且可以重复的集合。
List的主要实现:ArrayList, LinkedList, Vector。
常用方法
1.add()
向List集合中添加元素
list.add("孙千博");
System.out.println(list);
输出:[孙千博]
2.size()
获取集合中有多少个元素
int length = list.size();
System.out.println(length);
输出:1
3.get()
获取指定位置的元素(从0开始计数)
list.add("孙千博");
list.add("张三");
list.add("李四");
System.out.println(list.get(2));
输出:李四
4.add(int i,String str)
在指定位置添加元素,原来此位置的元素后移。
list.add("孙千博");
list.add("张三");
list.add("李四");
list.add(0,"帅气学长");
System.out.println(list.get(2));
输出:张三
5.set(int i,Object element)
替换指定位置的元素
list.add("孙千博");
list.add("张三");
list.add("李四");
list.set(2,"帅气学长");
System.out.println(list.get(2));
输出:帅气学长
6.clear()
清空List集合中的所有元素,不做演示了这个,就是把现有的元素清空
7.isEmpty()
判断集合中是否为空,返回boolean类型。集合为空,返回true;否则返回false。
8.contains(Object o)
判断集合中是否含有特定元素
没有返回false,否则返回true
list.add("孙千博");
list.add("张三");
list.add("李四");
boolean flag = list.contains("faker");
System.out.println(flag);
输出:
false
9.remove(int i)
删除指定位置的元素,并将此元素返回,并且后面元素前移。
list.add("孙千博");
list.add("张三");
list.add("李四");
list.set(2,"帅气学长")
String str = list.remove(0);
System.out.println(list);
输出:
[张三,帅气学长]
10.remove(Object o)
删除List集合中的某个特定元素,返回boolean类型,删除成功返回true,否则返回false,删除成功后,后面元素前移。跟上面的差不多,不做展示。
ArrayList, LinkedList, Vector的选择
简单来说,可以总结为以下:
增删多,LinkedList
改查多,ArrayList
ArrayList不同步,非线程安全,效率高,支持随机访问。 查询快,增删慢
LinkedList 不同步,非线程安全,效率高。查询慢,增删快
Vector同步,线程安全,效率低。查询快,增删慢
遍历的三种方式
1.普通for
2.增强for
3.迭代器iterator
三种方式的演示代码如下
import java.util.ArrayList;
import java.util.Iterator;
public class java0504 {
public static void main(String[] args) {
ArrayList<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
//第一种方式,普通for
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
//增强for
for(String name:list) {
System.out.println(name);
}
//迭代器
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
这三种方式都可以正确遍历集合中所有元素,结果太长了就不展示了(影响观看)
下面来说说在遍历的时候如果要增删元素应该怎么办
遍历时增删注意事项
细说普通for遍历
当我们用第一种方式增删元素时候
ArrayList<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if (s.equals("b")) {
list.remove(s);
}
}
System.out.println(list);
输出结果
[a, c, d, e, f]
我们可以看到,b被删除了
但是这种方式有一个缺点,当代码中有两个b紧靠着的时候,它只会删除第一个b,原因是当第一个元素b被删除后,它后面所有的元素都向前移动了一个单位,循环时导致第二个元素b漏掉了
细说增强for遍历
ArrayList<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
for (String s : list) {
if (s.equals("b")) {
list.remove(s);
}
System.out.println(s);
}
这种方式如果我们在遍历的时候增删元素会报错(ConcurrentModificationException),错误信息如下
a
b
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
at java.util.ArrayList$Itr.next(ArrayList.java:836)
at java_5.java0504.main(java0504.java:15)
进程已结束,退出代码1
简单来说,是因为在这里,foreach循环遍历容器本质上是使用迭代器进行遍历的,会对修改次数modCount进行检查,不允许集合进行更改操作
所以,在增删元素时候不能用增强for
细说迭代器遍历
先说一下结论,使用迭代器会避免以上两种错误
代码如下
ArrayList<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("b");
list.add("d");
list.add("e");
list.add("f");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("b")) {
it.remove();
}
}
System.out.println(list);
[a, d, e, f]
所以,我们以后如果想要在遍历的时候增删元素,推荐使用迭代器哦~
set接口
Set集合元素无序(存入和取出的顺序不一定一致),并且没有重复对象。
Set的主要实现类:HashSet, TreeSet。
常用方法
因为都是继承的collection接口,所以set接口里面的方法和list差不多,这里不做重复说明啦!
HashSet、TreeSet、LinkedHashSet的选择
一:HashSet
1.不能保证元素的排列顺序,顺序有可能发生变化
2.不是同步的,非线程安全
3.集合元素可以是null,但只能放入一个null
二:LinkedHashSet
1.LinkedHashSet中不能有相同元素,可以有一个Null元素,元素严格按照放入的顺序排列。
2.LinkedHashSet如何保证有序和唯一性?
1).底层数据结构由哈希表和链表组成。
2).链表保证了元素的有序即存储和取出一致,哈希表保证了元素的唯一性。
3.添加、删除操作时间复杂度都是O(1)。
4.非线程安全
三:TreeSet
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法
1.TreeSet是中不能有相同元素,不可以有Null元素,根据元素的自然顺序进行排序。
2.TreeSet如何保证元素的排序和唯一性?
底层的数据结构是红黑树(一种自平衡二叉查找树)
3.添加、删除操作时间复杂度都是O(log(n))
4.非线程安全
4丶Map接口
说明
Map是双列集合
Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap,关系类图已经在一开始给出(上面)
Map常用方法
1.put(key,value)
向集合中添加元素
scores.put("Tom", 100);//添加数据
scores.put("Kate", 60);
scores.put("Jim", 60);
2.size()
返回集合的长度
3.get(key)
输入key返回对应value,也可用于验证集合中是否有key,指定的键不存在的时候,返回的是null。
在这里插 Map<String,String> sqb = new HashMap<String,String>();
sqb.put("Tom", "60");//添加数据
sqb.put("Kate", "80");
sqb.put("Jim","70");
System.out.println(sqb.get("Tom"));入代码片
输出结果
60
进程已结束,退出代码0
4.replace(key,value),替换
通过key更新value,之前的就没有了
public static void main(String[] args) {
Map<String,String> sqb = new HashMap<String,String>();
sqb.put("Tom", "60");//添加数据
sqb.put("Kate", "80");
sqb.put("Jim","70");
System.out.println(sqb.get("Tom"));
sqb.replace("Tom","70");
System.out.println(sqb.get("Tom" ));
}
输出结果,可以看到已经替换成功了
60
70
进程已结束,退出代码0
5.isEmpty()
判断集合中是否有元素,若有则返回true;若没有,则返回false
6.clear()
清空集合中的所有元素
7.remove()
根据key移除map中的与该key对应的value
代码如下
public static void main(String[] args) {
Map<String,String> sqb = new HashMap<String,String>();
sqb.put("Tom", "60");//添加数据
sqb.put("Kate", "80");
sqb.put("Jim","70");
System.out.println(sqb.get("Tom"));
sqb.replace("Tom","70");
System.out.println(sqb.get("Tom" ));
sqb.remove("Tom");
System.out.println(sqb.get("Tom"));
}
输出结果
60
70
null
进程已结束,退出代码0
8.values()
获取Map集合所有的value
public class java0505 {
public static void main(String[] args) {
Map<String,String> sqb = new HashMap<String,String>();
sqb.put("Tom", "60");//添加数据
sqb.put("Kate", "80");
sqb.put("Jim","70");
System.out.println(sqb.values());
}
}
[60, 80, 70]
进程已结束,退出代码0
9.keySet()
获取Map集合所有的键(key)
代码如下
public static void main(String[] args) {
Map<String,String> sqb = new HashMap<String,String>();
sqb.put("Tom", "60");//添加数据
sqb.put("Kate", "80");
sqb.put("Jim","70");
System.out.println(sqb.keySet());
}
输出结果:
[Tom, Kate, Jim]
进程已结束,退出代码0
HashMap、TreeMap、HashTable区别
一:HashMap
线程不同步
允许 key 和 Vale 是 null,但是只允许一个 key 为 null,且这个元素存放在哈希表 0 角标位置
二:HashTable
同步
不允许key、value 是 null
TreeMap
线程不同步
value允许为null。
当未实现 Comparator 接口时,key 不可以为null
当实现 Comparator 接口时,若未对 null 情况进行判断,则可能抛 NullPointerException 异常。如果针对null情况实现了,可以存入,但是却不能正常使用get()访问,只能通过遍历去访问。
5丶Iterator接口
Iterator接口是用于遍历集合元素的接口。我们一般叫他迭代器,一般遍历集合有两种方式,迭代器是其中一种,另一种是增强for;
这个接口里面有三个方法
1: hasNext() 如果仍有元素可以迭代,则返回true。
2: next() 返回迭代的下一个元素。
3: remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
也就说,只要通过该接口就可以取出Collection集合中的元素进行操作,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性,
我们来看如何遍历,代码如下:
List<String> list1 = new ArrayList<>();
list1.add("a1");
list1.add("a2");
list1.add("a3");
// while循环方式遍历
Iterator it1 = list1.iterator();
while (it1.hasNext()) {
System.out.println(it1.next());
}
// for循环方式遍历
for (Iterator it2 = list1.iterator(); it2.hasNext(); ) {
System.out.println(it2.next());
}
使用Iterator迭代器进行删除集合元素,则不会出现并发修改异常。
三丶集合工具类Collections
这个类主要是为了方便对集合的操作。这个类不需要创建对象,内部提供的都是静态方法。
Collections.sort(list);//list集合进行元素的自然顺序排序。
Collections.sort(list,new ComparatorByLen());//按指定的比较器方法排序。
class ComparatorByLen implements Comparator<String>{
public int compare(String s1,String s2){
int temp = s1.length()-s2.length();
return temp==0?s1.compareTo(s2):temp;
}
}
Collections.max(list);//返回list中字典顺序最大的元素。
int index = Collections.binarySearch(list,"zz");//二分查找,返回角标。
Collections.reverseOrder();//逆向反转排序。
Collections.shuffle(list);//随机对list中的元素进行位置的置换。
集合的选用
各种集合的特点已经总结出来了,我们在使用的时候,主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用Map接口下的集合,需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选用ConcurrentHashMap.当我们只需要存放元素值时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,不需要就选择实现List接口的比如ArrayList或LinkedList,然后再根据实现这些接口的集合的特点来选用。
总结
总结到这里,但是我绝对各种集合的特点还是要经常复习,这样才能在以后根据需要选出最合适的集合。