Amadeus's Studio.

Java集合,泛型,spring注解、事务的一些问题

字数统计: 1.6k阅读时长: 6 min
2020/04/24 Share

java 集合类之间的继承关系

Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口。代表了两种不同的数据结构:集合和映射表。

collection

图中,ArrayList,HashSet,LinkedList,TreeSet是我们经常会有用到的已实现的集合类。

Map实现类用于保存具有映射关系的数据。Map保存的每项数据都是key-value对,也就是由key和value两个值组成。Map里的key是不可重复的,key用户标识集合里的每项数据。

map

迭代器的作用

由于Java中数据容器众多,而对数据容器的操作在很多时候都具有极大的共性,于是Java采用了迭代器为各种容器提供公共的操作接口

解耦效果:使用迭代器iterator可以使对容器的遍历操作完全与其底层相隔离,可以到达极好的解耦效果

iterator方法返回一个实现了Iterator接口的对象,作用是依次访问集合中的元素,Iterator接口包含3个方法:

1
2
3
boolean hasNext();  # 如果任有元素可以迭代,则返回true.
E next(); # 返回迭代的下一个元素
void remove(); # 从迭代器指向的collection中移除迭代器返回的最后一个元素(可选操作)

通过多次调用next()方法可遍历集合中的所有元素,需要注意的是需要在调用next()之前调用hasNext()方法,并在hasNext()返回true的时候才可以调用next().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args)
{
List<String> list=new ArrayList<>();
list.add("C++");
list.add("python");
list.add("java");
for(Iterator<String> it=list.iterator();it.hasNext();)
{
System.out.println(it.next());
if(xxx){
list.remove();//翻车写法
it.remove();//正确写法
}
}
}

遍历集合时删除特定元素一定要用Iterator的remove,别用集合自带的remove。会报错:

java.util.ConcurrentModificationException
在集合内部维护一个字段modCount用于记录集合被修改的次数,每当集合内部结构发生变化(add,remove,set)时,modCount+1。  
在迭代器内部也维护一个字段expectedModCount,同样记录当前集合修改的次数,初始化为集合的modCount值。当我们在调用Iterator进行遍历操作时,如果有其他线程修改list会出现modCount!=expectedModCount的情况,就会报并发修改异常java.util.ConcurrentModificationExceptionConcurrentModificationException

集合的排序

java集合的工具类Collections中提供了两种排序的方法,分别是:

  1. Collections.sort(List list)

  2. Collections.sort(List list,Comparator c)

第一种称为自然排序,参与排序的对象需实现comparable接口,缺点会入侵代码

第二种叫定制排序,或自定义排序,需编写匿名内部类,先new一个Comparator接口的比较器对象,优点不用修改排序对象代码,例子:

1
2
3
4
5
6
Collections.sort(ordered, new Comparator<Student>() {
@Override
public int compare(Student t1, Student t2) {
return (int) (t1.getOrder() - t2.getOrder());
}
});

java8函数式排序

1
2
//根据学生身高排序
list.sort(Comparator.comparing(Student::getHeight).reversed())

泛型

泛型类

1
2
3
4
5
6
7
8
class Demo<T>{
public T fun(T t){
return t;
}
public <T> T fun2(T t){
return t;
}
}

泛型类的方法泛型方法区别:

  • 一个是在实例化对象才确认下来的 【泛型类的方法】
  • 一个是在方法调用时确认下来的 【泛型方法】

普通泛型类的方法

1
2
3
4
// 虽然方法中使用了泛型,但这并不是泛型方法
public T fun(T t){ // 可以接收任意类型的数据
return t; // 直接把参数返回
}

加static会编译错误

泛型方法

可以加static

1
2
3
4
// 这个<T>修饰的方法才是真的泛型方法
public static <T> T fun2(T t){ // 可以接收任意类型的数据
return t; // 直接把参数返回
}

泛型方法总结

  • 泛型类,是在 【实例化类】 的时候指明泛型的具体类型;
  • 泛型方法,是在调用方法的时候指明泛型的具体类型 ,注意跟类实例化没关系了。
  • 泛型方法可以加static,普通的泛型类的方法是不可以的

使用泛型方法好处

  • 因为泛型方法类型可以灵活的传入参数类型,不像泛型类的方法实例化后就固定掉了。
  • 每次调用泛型方法入参类型都可以灵活的变化,可以看我的例子
  • 泛型方法支持static

spring注解、事务传播机制

7种事务的传播机制(可通过spring配置或注解来设置)

  1. REQUIRED(默认):支持使用当前事务,如果当前事务不存在,创建一个新事务。
  2. SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务。
  3. MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。
  4. REQUIRES_NEW:创建一个新事务,如果当前事务存在,把当前事务挂起。
  5. NOT_SUPPORTED:无事务执行,如果当前事务存在,把当前事务挂起。
  6. NEVER:无事务执行,如果当前有事务则抛出Exception。
  7. NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。

事务注解失效的例子

1
2
3
4
5
6
7
8
9
10
11
12
13

public class WePageManagerServiceImpl implements WePageManagerService {

@Override
public void pagePublish(MysRequest request) {
PublishHandler(request);
}

@Transactional(rollbackFor = Exception.class)
protected ProcResult<String> PublishHandler(WePagePublishRequest request) {
//多表dao操作......
}
}

解决方案:把事务代码下沉,用一个类去单独处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class WePageManagerServiceImpl implements WePageManagerService {

@Autowired
private MyTransaction myTransaction;

@Override
public void pagePublish(MysRequest request) {
myTransaction.pagePublishHandler(request);
}
}

@Service
@Transactional(rollbackFor = Throwable.class)
public class MyTransactionImpl implements MyTransaction{
protected ProcResult<String> pagePublishHandler(WePagePublishRequest request) {
//多表dao操作......
}
}

@Transactional失效原因分析:自身调用导致失败

在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,再由这个代理对象来统一管理,当在Service实现类直接调用内部方法时,其本质是通过this对象来调用的方法,而不是代理对象,因为会出现事务失效的情况

总结一句话,自身调用没有经过 Spring 的代理类

事务失效3种常见原因

  • 自身调用(面试最爱问啦)
  • 异常被吃
  • 异常抛出类型

参考内容-微信

CATALOG
  1. 1. java 集合类之间的继承关系
  2. 2. 迭代器的作用
  3. 3. 集合的排序
  4. 4. 泛型
    1. 4.1. 普通泛型类的方法
    2. 4.2. 泛型方法
    3. 4.3. 泛型方法总结
    4. 4.4. 使用泛型方法好处
  5. 5. spring注解、事务传播机制
    1. 5.1. 7种事务的传播机制(可通过spring配置或注解来设置)
    2. 5.2. 事务注解失效的例子
    3. 5.3. 解决方案:把事务代码下沉,用一个类去单独处理