一、匿名内部类
匿名内部类可以使你的代码更加简洁,你可以在定义一个类的同时对其进行实例化。它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要用一次,那么你就可以使用匿名内部类。
入门理解参考:https://www.jianshu.com/p/0950c6787c7d
另参考:
https://www.cnblogs.com/wuhenzhidu/p/anonymous.html
二、泛型通配符extends与super的区别
java泛型中的关键字
1、? 表示通配符类型
2、<? extends T> 既然是extends,就是表示泛型参数类型的上界,说明参数的类型应该是T或者T的子类。
3、<? super T> 既然是super,表示的则是类型的下界,说明参数的类型应该是T类型的父类,一直到object。
extends 可用于的返回类型限定,不能用于参数类型限定。
super 可用于参数类型限定,不能用于返回类型限定。
希望只取出get,不插入,就使用? extends
希望只插入add,不取出,就使用? super
希望,即能插入,又能取出,就不要用通配符?
参考:https://www.cnblogs.com/songpingyi/p/10002018.html
三、Map的 entrySet()、map遍历
Entry
由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。
Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value (我们总说键值对键值对, 每一个键值对也就是一个Entry)
Map.Entry里面包含getKey()和getValue()方法
entrySet
entrySet是 java中 键-值 对的集合,Set里面的类型是Map.Entry,一般可以通过map.entrySet()得到。
entrySet实现了Set接口,里面存放的是键值对。一个K对应一个V。
keySet
还有一种是keySet, keySet是键的集合,Set里面的类型即key的类型
四种遍历Map方式:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();map.put("1", "value1");map.put("2", "value2");map.put("3", "value3");//第一种:普遍使用,二次取值System.out.println("通过Map.keySet遍历key和value:");for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));}//第二种System.out.println("通过Map.entrySet使用iterator遍历key和value:");Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());}//第三种:推荐,尤其是容量大时System.out.println("通过Map.entrySet遍历key和value");for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());}//第四种System.out.println("通过Map.values()遍历所有的value,但不能遍历key");for (String v : map.values()) {
System.out.println("value= " + v);}}
参考:https://blog.csdn.net/q5706503/article/details/85122343
另:
HashMap合并相同key的value
https://www.cnblogs.com/felixzh/p/6019444.html
Json数组形式的字符串转为Map数组 Map集合的几种遍历方式
https://www.cnblogs.com/codingmode/p/13098509.html
四、replaceAll中特殊字符串
public String replaceAll(String regex,String replacement)
***参数***
regex - 要匹配此字符串的正则表达式
replacement - 要替换每个匹配的字符串
用给定的替换替换与给定的regular expression匹配的此字符串的每个子字符串。
比如常用的
"要用\"
我用到的是
puts("a{b","a{b".replaceAll("\\{", "33{44")); //左大括号需要转义
结果:a{
b a33{
44b
ReplaceAll 特殊字符处理:https://www.cnblogs.com/hua198/p/5907286.html
五、AtomicInteger类
定义:AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。
AtomicInteger是在使用非阻塞算法实现并发控制,在一些高并发程序中非常适合,但并不能每一种场景都适合,不同场景要使用使用不同的数值类。
注意:高并发的情况下,i++无法保证原子性,往往会出现问题,所以引入AtomicInteger类。
具体例子和类的方法参考:https://www.cnblogs.com/ziyue7575/p/12213729.html
六、jsonobject和map转换
1、jsonobject->map
//json字符串
String jsondata="{\"contend\":[{\"bid\":\"22\",\"carid\":\"0\"},{\"bid\":\"22\",\"carid\":\"0\"}],\"result\":100,\"total\":2}";
JSONObject obj= JSON.parseObject(jsondata);
//map对象
Map<String, Object> data =new HashMap<>();
//循环转换Iterator it =obj.entrySet().iterator();while (it.hasNext()) {
Map.Entry<String, Object> entry = (Entry<String, Object>) it.next();data.put(entry.getKey(), entry.getValue());}
System.out.println("map对象:"+data.toString());// 结果:{total=2, contend=[{"carid":"0","bid":"22"},{"carid":"0","bid":"22"}], result=100}
2、map->jsonobject
//map对象
Map<String, Object> data =new HashMap<>();
String x =JSONObject.toJSONString(data);
System.out.println("json字符串:"+x);//结果:{"total":2,"result":100,"contend":[{"carid":"0","bid":"22"},{"carid":"0","bid":"22"}]}
参考:https://blog.csdn.net/qq_38111316/article/details/88898527
https://blog.csdn.net/qq_41334351/article/details/95956065
七、Function.identity()
Function是一个接口,那么Function.identity()是什么意思呢?解释如下:
Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default方法和static方法,identity()就是Function接口的一个静态方法。
Function.identity()返回一个输出跟输入一样的Lambda表达式对象,等价于形如
t -> t形式的Lambda表达式。
我是去重时会用到(同一标题的几条数据,只返回id更大那个.collect(Collectors.toMap(DataSetResponse::getName, Function.identity(), (d1, d2) -> d1.getId() > d2.getId() ? d1 : d2));
)。
参考:https://www.jianshu.com/p/cd694d2d8be5
八、ConcurrentHashMap
为什么要使用ConcurrentHashMap。
在并发编程中使用HashMap可能导致程序死循环。而使用线程安全的HashTable效率又非常低下,基于以上两个原因,便有了ConcurrentHashMap的登场机会
1)线程不安全的HashMap
在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。HashMap在并发执行put操作时会引起死循环,是因为多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环形数据结构,Entry的next节点永远不为空,就会产生死循环获取Entry。
2)效率低下的HashTable
HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法,其他线程也访问HashTable的同步方法时,会进入阻塞或轮询状态。如线程1使用put进行元素添加,线程2不但不能使用put方法添加元素,也不能使用get方法来获取元素,所以竞争越激烈效率越低。
3)ConcurrentHashMap的锁分段技术可有效提升并发访问率
HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术。首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
另:
1、get方法不加锁;
2、put、remove方法要使用锁
jdk7使用锁分离机制(Segment分段加锁)
jdk8使用cas + synchronized 实现锁操作
3、Iterator对象的使用,运行一边更新,一遍遍历(可以根据原理自己拓展)
4、复合操作,无法保证线程安全,需要额外加锁保证
5、并发环境下,ConcurrentHashMap 效率较Collections.synchronizedMap()更高
ConcurrentHashMap解析参考:https://www.jianshu.com/p/1e1a96075256
另参考:https://blog.csdn.net/ym123456677/article/details/78860719