Week Two
日期类 Java.time
- LocalTime
- LocalDate
- LocalDateTime
- DateTimeFormatter
LocalDate
LocalDate类用于表示一个标准格式日期,通常以“yyyy-MM-dd”格式显示(如2020-7-10),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);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TKsepW6T-1594559849302)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1594553200404.png)]
LocalTime
LocalTime类用于表示一个标准格式时间,通常以"HH:mm:ss.SSSS"格式显示(如:11:22:33.354)LocalTime的使用方法:
LocalTime time = LocalTime.now();
//获取时
System.out.println("当前时:" + time.getHour());
//获取分
System.out.println("当前分:" + time.getMinute());
//获取秒
System.out.println("当前秒:" + time.getSecond());
//根据指定的日期构建一个LocalTime对象
LocalTime time1 = LocalTime.of(12,11,18);
System.out.println("设置的时间为:" + time1);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vQOhr1zK-1594559849304)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1594554208668.png)]
LocalDateTime
LocalDateTime类用于表示一个标准日期时间格式,通常以yyyy-MM-ddTHH:mm:ss.SSS格式显示(如:2020-08-07T18:18:18),LocalDateTime的使用方法:
//将LocalDateTime 转换为 LocalDate
LocalDate localDate = time.toLocalDate();
//将LocalDateTime 转换为 LocalTime
LocalTime localTime = time.toLocalTime();
System.out.println("DateTime转换为Date:" + localDate);
System.out.println("\nDateTime转换为Time:" + localTime);
//根据指定的日期构建一个LocalDateTime对象
LocalDateTime time1 = LocalDateTime.of(2020,8,9,19,22,12);
System.out.println("\n设置的LocalDateTime对象:" + time1);`
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XCblBuQe-1594559849306)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1594555305066.png)]
DateTimeFormatter
DateTimeFormatter是jdk8新增java.time包中的一个用于对LocalDate,LocalTime,LocalDateTime进行格式化和解析的解析类,内部体提供一些内置的格式化方式,比如:
- BASIC_ISO_DATE
- ISO_DATE
- ISO_INSTANT
- ISO_LOCAL_DATE
同时该类还支持自定义的格式化匹配模式,通过以下方法获得:
- ofPattern(String pattern)
例如:
//获取系统时间: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));
注意事项:
与DateFormat和SimpleDateFormat的区别在于,DateTimeFormatter是线程安全的实现,在多线程并发的时候可以让多个线程使用同一当前实例,能保证数据的一致性;但是DateFormat是线程非安全实现,因此在多线程并发时,需要为每个线程单独创建该实例。
正则表达式
正则表达式最早起源于perl语言,内部包含一种特殊的字符串格式能够对特定的字符串内容进行解析,替换,查找等等功能,比如判断一个字符串是否是手机号,会使用如下正则表达式:
- ^1[356789]\d{9}$
正则表达式是独立于语言的第三方技术(跟使用的编程语言无关);目前几乎所有的编程语言都支持正则表达式。
正则表达式是一门十分强大的表达式语言,在很多实际场景中常见,比如:填写表达式验证输入内容的格式(手机号格式,邮箱地址格式),微博的话题,聊天信息的表情提取,敏感词的过滤,网络爬虫;正则表达式的使用场景分为三种:
- 查找
- 替换
- 验证
java中使用正则表达式一下以下几个类
- java.lang.String
- java.util.regex.Pattern
- java.util.regex.Matcher
String类中哪些方法使用到了正则表达式:
- split
- replace
- matches
public class RegexDemo {
public static void main(String[] args) {
System.out.println("15456543212".matches("^1\\d{10}$"));
//任何一个字符串实际都是一个正则表达式
System.out.println("a".matches("a"));
//匹配数字
System.out.println("1".matches("[0-9]"));
System.out.println("1".matches("\\d"));
//匹配非数字
System.out.println("0".matches("\\D"));
System.out.println("%".matches("[^0-9]"));
//验证输入的内容只能是abc中的一个字母?
System.out.println("b".matches("[abc]"));
//验证内容是否是小写的单词
System.out.println("f".matches("[a-z]"));
//验证内容只能是数字和字母
System.out.println("$".matches("[0-9A-Za-z]"));
System.out.println("0".matches("\\w"));
//判断文本内容是否是换行标记
System.out.println("\n".matches("\\n"));
//匹配空白字符(\n \r \t)
System.out.println("\r".matches("\\s"));
System.out.println("lo".matches("lo\\b"));
}
}
注意事项:
java中的所有正则表达式在正常工作之前,都需要先编译,编译的过程通过Pattern类实现
Pattern & Matcher
在日常使用正则表达式时,String中matches方法虽然能够满足部分需求(匹配),但是针对一些特殊需求,比如说,筛选等功能不能实现,因此,jdk中针对正则表达式的使用还提供了两个类:
- Pattern :提供针对正则表达式的编译功能
- Matcher:提供对已经编译过的正则表达式匹配字符串的功能
Pattern和Matcher使用
String s = "asdiu1323479827348917612312312318912314213131231231sajffasdf";
//对正则表达式编译获取匹配模式对象
Pattern p = Pattern.compile("1\\d{10}");
System.out.println(p.pattern());
//使用匹配模式对指定制服穿进行匹配获取匹配器
Matcher m = p.matcher(s);
//将字符串序列跟整个模式匹配
System.out.println(m.matches());
//从匹配器中寻找符合匹配模式的字符串,如果能找到则返回true
while(m.find()) {
//返回匹配的字符串内容
String phone = m.group();
System.out.println(phone);
}
//运行结果:
//13234798273
//17612312312
//18912314213
group(组)
组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
public static void main(String[] args) {
String score="109:89/99-120";
String regex = "((\\d{1,3}):(\\d{1,3}))/((\\d{1,3})-(\\d{1,3}))";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(score);
System.out.println(m.groupCount());
//开始查找
m.find();
//整组匹配
System.out.println(m.group());
System.out.println(m.group(0));
//按照分组匹配
System.out.println(m.group(1));
System.out.println(m.group(2));
System.out.println(m.group(3));
System.out.println(m.group(4));
System.out.println(m.group(5));
System.out.println(m.group(6));
//现有3个球队比分,在一个字符串中表示,现要求从以下比分中别获取每场比分的结果
//并获取每个队伍的分数,分数不能从0开始
// 100:66/89:98/77:65
}
泛型(Generic)
泛型即参数化类型,在JDK1.5之后引入了泛型的概念,参数化类型即将一种数据类型以参数形式传递到类,接口或者方法中,可以将对于数据类型的检查从运行期间提前到编译期,java中的泛型使用分为三种情况:
- 泛型接口
- 泛型类
- 泛型方法
泛型标记命名是可以自定义的,JDK对一些常见的泛型有以下定义:
- T 类型(Type)
- E 元素(Element)
- K 键(Key)
- V 值(Value)
泛型类
在类声明时在后面通过<>
符号指定类型参数,然后在类中可以使用这些类型参数设置动态类型
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 DeptManager implements BaseManager<Dept>{
@Override
public boolean add(Dept obj) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean delete(Dept obj) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean update(Dept obj) {
// TODO Auto-generated method stub
return false;
}
@Override
public Dept findById(int id) {
// TODO Auto-generated method stub
return null;
}
@Override
public ArrayList<Dept> 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
JVM没有泛型的概念,泛型只存在于编译器编译期间,java实现泛型使用的是类型擦除,在编译期间由编译器识别泛型,并做出处理,到JVM之前或擦除所有的类型,例如:
ArrayList<String> list1 = new ArrayList<>();
list1.add("rose");
list1.add("jack");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(10);
list2.add(100);
System.out.println(list1.getClass() == list2.getClass());//true
System.out.println(list1.getClass());
System.out.println(list2.getClass());
ArrayList<CharSequence> list3 = list; //编译错误
对以上的需求,如果需要成立时:
ArrayList<CharSequence> list3 = list;
泛型中引入统配符的概念:
- ?
- <? extends T>
- <? super T>
具体使用如下:
public class Demo {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("rose");
list1.add("jack");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(10);
list2.add(100);
//上界限定:只能取值不能存值(只出不进)
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);
System.out.println(obj);
}
}
集合(容器)框架入门
概述
在JDK1.2之前,java中已经支持一些容器技术,数组,向量,哈希表,字典,枚举:
- 枚举(Enumeration)
- 向量(Vector)
- 栈(Stack)
- 哈希表(Hashtable)
- 字典(Dictionary)
- 属性表(Properties)
由于老版的集合API存在一些设计缺陷(线程并发,存储空间问题),以及没有一个统一的主线;所以从JDK1.2开始jDK中新增集合框架概念。并且将整个集合相关技术统一称为一条主线(大量使用接口技术)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CRu0gSz9-1594559849311)(D:\带班资料\2020\j2003\线下\part1-JavaSE\20200709\笔记\assets\1594259477688.png)]
Java1.0
Java1.2: J2SE J2ME J2EE
Java1.5:JavaSE JavaME javaEE
Collection接口
Collection是java集合框架中的顶层接口,用于表示一些相同类型的数据集合,内部提供了一系列用于对集合中元素进行存储的方法。
Collection接口的常见方法;
- add(E e) 添加元素
- 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是一个接口,所以没法直接实例化,因此JDK中提供了一些对于List接口实现的实现类:
- ArrayList
- LinkedList
ArrayList
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f8fYIttV-1594559849312)(D:\带班资料\2020\j2003\线下\part1-JavaSE\20200709\笔记\assets\1594281849988.png)]
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);
}
ArrayList是线程不安全(不同步)的List实现,如果需要线程同步可以考虑:
- Vector(淘汰)
- CopyOnWriteArrayList
ArrayList使用
LinkedList
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5MVs1NO0-1594559849313)(D:\带班资料\2020\j2003\线下\part1-JavaSE\20200709\笔记\assets\1594281871228.png)]
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)
迭代器即游标,将集合处理为类似栈结构的数据结构,通过栈顶指针依次向下搜索元素,直到达到栈底为止
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kVeruX8-1594559849314)(C:\Users\admin\Desktop\note\迭代器.png)]
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);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eSLmXpyt-1594559849319)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1594556198282.png)]
集合排序
Java对元素的排序提供了两个用于实现集合排序的接口:
- java.util.Comparator
- java.lang.Comparable
通过对以上接口的实现结合集合中提供的相关方法即可完成排序操作
Comparator
java.util.Comparator是JDK1.2提供的接口,内部包含一个用于实现排序的方法:
- compare(e1,e2)
通过对该接口实现可以完成个性化排序的需求,只需要实现接口中compare方法,根据该方法的返回值决定元素的排序顺序,具体使用如下:
定义比较器(MyComparator)
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]
集合排序与Collections类
集合排序(续)
在对集合排序时除了使用java.util.Comparator接口自定义比较规则外,还可以通过java.lang包中提供的Comparable接口,针对需要实现排序的类型对该接口实现之后,并实现内部的compareTo方法可以自定义排序规则,最后通过Collections提供sort方法将需要排序的集合(List)传入即可。
具体使用方式:
-
声明需要具备排序能力实体类,实现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 + "]"; } }
-
实现排序
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)); } }
执行结果:
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);
}
}
Collection、Collections、Connection区别?
Collection是JDK1.2之后新增的集合框架的顶层接口
Collections是一个用于对集合进行处理的工具类
Connection是在JDBC中用于操作数据的一个连接接口
基于Pinyin4J实现中文排序
对中文内容排序需要使用到一个开源插件(jar包)-Pinyin4j
- pinyin4j-2.5.0.jar
使用流程
- 将jar文件复制到项目根目录下(推荐创建lib目录,并放到lib目录中)
- 将jar文件添加到构建路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sN2c3r5S-1594559849320)(D:\带班资料\2020\j2003\线下\part1-JavaSE\20200710\笔记\assets\1594349157168.png)]
示例代码:
String s = "软帝";//ruan3di4
//将指定的中文字符转换为字符串数组(中文字符的多种读音的拼音表达形式)
String[] py = PinyinHelper.toHanyuPinyinStringArray(s.charAt(0));
for (String c : py) {
System.out.println(c); //ruan3
}
//声明字符串用于临时存储转换之后汉语拼音字符串
String str = "";
//遍历获取每一个字符
for (int i = 0; i < s.length(); i++) {
String[] info = PinyinHelper.toHanyuPinyinStringArray(s.charAt(i));
//将每个汉字的第一个拼音读音拼接到一起
str += info[0];
}
System.out.println(str);//ruan3di4
中文排序示例:
List<String> names = new ArrayList<>();
names.add("柴老师");
names.add("王老师");
names.add("苍老师");
names.add("老王");
names.add("老李");
names.add("小泽老师");
Collections.sort(names,(s1,s2)->{
String p1 = "";
String p2 = "";
for(int i = 0;i<s1.length();i++) {
p1 += PinyinHelper.toHanyuPinyinStringArray(s1.charAt(i))[0];
}
for(int i = 0;i<s2.length();i++) {
p2 += PinyinHelper.toHanyuPinyinStringArray(s2.charAt(i))[0];
}
return p1.compareTo(p2);
});
System.out.println(names);
运行结果:
[苍老师, 柴老师, 老李, 老王, 王老师, 小泽老师]
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
在Map接口出现之前,JDK中存在类似键值对结构:
- Dictionary
- Properties
- Hashtable
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一样,不允许空键值存在,实现线程同步的实现,运行效率较低
java.util.concurrent.ConcurrentHashMap(并发编程)