Arrays.asList 的坑 java.lang.UnsupportedOperationException/list剔除数据/UUID正确的生成方式,批量使用重复问题

本文详细解析了使用Arrays.asList创建List对象时出现UnsupportedOperationException异常的原因及解决方案,同时介绍了正确删除List元素的方法,并探讨了批量设置UUID时可能出现的问题及解决策略。
  1. Arrays.asList

在项目中对List进行操作时报错java.lang.UnsupportedOperationException,后来发现操作的List是由数组转换而成的,通过看源码发现问题,并写测试程序如下。
代码块:

public class ListTest {
    public static void main(String[] args) {
        String[] array = {"1","2","3","4","5"};
        List<String> list = Arrays.asList(array);
        list.add("6");
    }
}

执行结果:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)
    at com.atguigu.test.ListTest.main(ListTest.java:11)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

发生问题的原因如下:
调用Arrays.asList()生产的List的add、remove方法时报异常,这是由Arrays.asList() 返回的市Arrays的内部类ArrayList, 而不是java.util.ArrayList。Arrays的内部类ArrayList和java.util.ArrayList都是继承AbstractList,remove、add等方法AbstractList中是默认throw UnsupportedOperationException而且不作任何操作。java.util.ArrayList重新了这些方法而Arrays的内部类ArrayList没有重新,所以会抛出异常。解决方法如下:

public class ListTest {
    public static void main(String[] args) {
        String[] array = {"1","2","3","4","5"};
        List<String> list = Arrays.asList(array);
        List arrList = new ArrayList(list);
        arrList.add("6");
    }
}

或者

	@Test
	public void test2021() {
		List<String> list = new ArrayList<>( Arrays.asList("1","2","3","4","7","8","9","ss","dsd","dsds","dsds","dsds"));		
		//一定要用arrayist
		list.remove(0);
		System.out.println(StringUtils.join(list.toArray()));
	}
  1. list查询剔除数据
    参考资料
    首先准备数据:
    public static List<User> createList(){
        List<User> result =new ArrayList<>();
        result.add(new User(1,"peter","123","二狗"));
        result.add(new User(2,"lilei","123","铁柱"));
        result.add(new User(3,"lilei","123","大炮"));
        result.add(new User(4,"jonhs","123","大虎"));
        return result;
    }```
剔除名字为lilei的数据
 错误的执行方式
 

```sql
    //从例表中剔除lilei的数据
    public static void main(String[] args) {
        List<User> list = createList();
        for(int i  = 0 ; i < list.size() ; i++){
            String temp = list.get(i).getUserName();
            if(temp.equals("lilei")){
                list.remove(i);
            }
        }
      }

执行结果为

[User{id=1, userName='peter', passWord='123', realName='二狗'}, User{id=3, userName='lilei', passWord='123', realName='大炮'}, User{id=4, userName='jonh', passWord='123', realName='大虎'}]

可见并没有剔除干净,从list中剔除数据最好使用迭代器 Iterator
正确的书写方式为:

        Iterator<User> iterator = list.iterator();
        while(iterator.hasNext()){
            User next = iterator.next();
            if(next.getUserName().equals("lilei")){
                iterator.remove();
            }
        }
        System.out.println(list.toString());

结果为

[User{id=1, userName='peter', passWord='123', realName='二狗'}, User{id=4, userName='jonhs', passWord='123', realName='大虎'}]

  1. UUID
    UUID在一般情况下是不会重复的 即使是用版本4 ,但是遇到批量操作的时候会产生重复,短时间内大量的调用该方法,造成了多线程调用,使多个数据获取到同一个UUID,造成UUID重复,就需要加synchronized同步锁来将同步改为异步,具体实现如下(包括多种版本实现方式,选取一种版本即可):

	//synchronized 同步锁  UUID一般是不会重复的 即使是用版本4 
	//但是当批量设置UUID时,短时间内大量的调用该方法,造成了多线程调用,使多个数据获取到同一个UUID,造成UUID重复
	@Test
	public synchronized void uuidTest() {
		// 最普遍的UUID 
		// version=4
		System.out.println(UUID.randomUUID().version());
		// 32位bd22291e39eb4736a55991497c6376d2
		System.out.println(UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
		// 基于时间的UUID 可以精确到毫微秒
		TimeBasedGenerator gen = Generators.timeBasedGenerator(EthernetAddress.fromInterface());
		UUID uuid = gen.generate();
		// version=1
		System.out.println(uuid.version());
		// 32位33304096c01311e58c16089e01cd1de9
		System.out.println(uuid.toString().replaceAll("-", "").toUpperCase());

		try {
			System.out.println(MD5Util.md5Encode(UUID.randomUUID().toString() + gen.generate().toString()));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
package com.msb.redis.lock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.params.SetParams; import java.util.Arrays; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; /** * 分布式锁的实现 */ @Component public class RedisDistLock implements Lock { private final static int LOCK_TIME = 5*1000; private final static String RS_DISTLOCK_NS = "tdln:"; /* if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end */ private final static String RELEASE_LOCK_LUA = "if redis.call('get',KEYS[1])==ARGV[1] then\n" + " return redis.call('del', KEYS[1])\n" + " else return 0 end"; /*保存每个线程的独有的ID值*/ private ThreadLocal<String> lockerId = new ThreadLocal<>(); /*解决锁的重入*/ private Thread ownerThread; private String lockName = "lock"; @Autowired private JedisPool jedisPool; public String getLockName() { return lockName; } public void setLockName(String lockName) { this.lockName = lockName; } public Thread getOwnerThread() { return ownerThread; } public void setOwnerThread(Thread ownerThread) { this.ownerThread = ownerThread; } @Override public void lock() { while(!tryLock()){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void lockInterruptibly() throws InterruptedException { throw new UnsupportedOperationException("不支持可中断获取锁!"); } @Override public boolean tryLock() { //锁的重入,虽然这段代码进行了锁重入检查,但它并没有实际完成锁的获取操作。上述代码只是进行了一个判断, // 告知调用者当前线程是否可以获取锁,但并没有对锁的状态进行更新。后续添加锁的操作是为了真正地获取锁资源, // 更新锁的状态,确保在多线程环境下对共享资源的安全访问。 Thread t = Thread.currentThread(); if(ownerThread==t){/*说明本线程持有锁*/ return true; }else if(ownerThread!=null){/*本进程里有其他线程持有分布式锁*/ return false; } Jedis jedis = null; //加锁 try { String id = UUID.randomUUID().toString(); SetParams params = new SetParams(); params.px(LOCK_TIME); params.nx(); synchronized (this){/*线程们,本地抢锁*/ if((ownerThread==null)&& "OK".equals(jedis.set(RS_DISTLOCK_NS+lockName,id,params))){ lockerId.set(id); setOwnerThread(t); return true; }else{ return false; } } } catch (Exception e) { throw new RuntimeException("分布式锁尝试加锁失败!"); } finally { jedis.close(); } } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { throw new UnsupportedOperationException("不支持等待尝试获取锁!"); } @Override public void unlock() { if(ownerThread!=Thread.currentThread()) { throw new RuntimeException("试图释放无所有权的锁!"); } Jedis jedis = null; try { jedis = jedisPool.getResource(); Long result = (Long)jedis.eval(RELEASE_LOCK_LUA, Arrays.asList(RS_DISTLOCK_NS+lockName), Arrays.asList(lockerId.get())); if(result.longValue()!=0L){ System.out.println("Redis上的锁已释放!"); }else{ System.out.println("Redis上的锁释放失败!"); } } catch (Exception e) { throw new RuntimeException("释放锁失败!",e); } finally { if(jedis!=null) jedis.close(); lockerId.remove(); setOwnerThread(null); System.out.println("本地锁所有权已释放!"); } } @Override public Condition newCondition() { throw new UnsupportedOperationException("不支持等待通知操作!"); } } 代码解读
最新发布
11-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PH = 7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值