分类 Default 下的文章

很久之前就用Docsify写过一篇java的文档(卒),过了一段时间后再想动手,发现已经不会用Docsify

现在网上使用的类似文档有很多:gitbook、书栈、看云等等,之所以选了Docsify,也是之前学习Vue才知道有这东西,认真看了下,也还不错。

仅仅是为了记录和复习一下,毕竟-->官方文档<--已经写得很清楚了。

下面是鱼某人利用几个晚上时间写的Docsify使用记录文档,肯定还有疏漏的地方,欢迎直接在文档下面留言哟。

https://bookstack.shafish.cn/docsify-reference/#/

Ref: https://docsify.js.org/#/

先写完Docsify再到Springsecurity,都在计划内,后续继续写Java基础相关文档、Spring相关的框架文档、云服务和大数据或者其他语言(Rust,Go)的文档,之前的坑会一个个填完的,不填完就--( *・ω・)✄╰ひ╯

实际开发中遇到的问题,仅此记录

map中对Arrays.asList的结果集合进行操作无效。 知识点太久没复习,一不小心就掉咧。完整测试代码

一、出现问题

// 需求要删掉map中key值跟数组元素相同的数据。
Integer[] idsInt = {2, 3};

Map<Integer, String> map = HashMap<>();
map.put(1,"hello");
map.put(2,"world");
map.put(3,"go");
map.put(4,"ahead");

map.keySet().removeIf(v -> Arrays.asList(idsInt).contains(v)); 
// 最后结果应该只有key为1、4的数据。
// 然而结果是所有map原始数据(key1~key4)

二、定位问题

removeIf

这个方法是java8中新增。直接写死参数看结果:
map.keySet().removeIf(v -> v==2); 确实key为2的数据被删了,确实是可以删除数据的,pass继续。

Arrays.asList

  • 因为用到了lambda表达式,分析的时候有点卡-->lambda表达式复习
    v -> Arrays.asList(idsInt).contains(v)
  • 先来分析 ->,这是一个Predicate函数,执行test方法,返回boolean类型。所以完整的v -> Arrays.asList(idsInt).contains(v)执行流程是:

    map.keySet().removeIf(new Predicate<Integer>() {
      @Override
      public boolean test(Integer v) {
          return Arrays.asList(idsInt).contains(v);
      }
    });
  • 来看看Arrays.asList代码

    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
      return new ArrayList<>(a);
    }

    返回了一个ArrayList数组集合,没毛病。

结合代码,如果key存在于该数组中,就返回true,返回true就执行删除操作。为什么没有删掉呢?

再退回来看map.keySet().removeIf代码

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
        if (filter.test(each.next())) { // 在此处调用了lambda表达式,如果包含则返回true
            each.remove();
           removed = true;
        }
   }
    return removed;
}
最终map.keySet().removeIf(v -> Arrays.asList(idsInt).contains(v)); 的代码执行流程如下:
removeIf(Predicate<Integer> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<Integer> each = iterator();
    while (each.hasNext()) {
        // if(filter.test(each.next())) 等于
        if (Arrays.asList(idsInt).contains(each.next())) {
            // 这里调用了迭代器的remove方法对Arrays.asList的结果集进行了remove操作
            // 迭代器使用的注意事项:不能调用集合的remove方法改变集合,否则会ConcurrentModificationException
            each.remove();  
            removed = true;
        }
    }
    return removed;
}
map.keySet().removeIf(Predicate..);

发现问题

  • removeIf方法的if语句中Arrays.asList返回了一个数组集合,数组集合增删查改应该没问题才对。然鹅,当按住ctrl键点击该ArrayList类时,并不是跳转到java.util.ArrayList类!!!
  • 而是跳转到Arrays私有的内部类(这个内部类紧接着asList方法,滑稽),其路径为:java.util.Arrays中的ArrayList内部类

    private static class ArrayList<E> extends AbstractList<E>
          implements RandomAccess, java.io.Serializable {
      xxxx //并没有增删方法
    }
  • 因为该内部类继承了List的实现类AbstractList,所以该内部类ArrayList有List所有定义的方法可以调用,List中存在remove方法的定义,但是在ArrayList内部类中该定义没有被实现。所以就发生了删不了数据的情况!!

三、解决方法

原来的代码:map.keySet().removeIf(v -> Arrays.asList(idsInt).contains(v));可修改为下面代码使用:

第一种方法:
map.keySet().removeIf(v -> {
    for(int j=0;j<idsInt;j++) 
        if(j == v) return true;
    return false;
});
  • 把集合相关的操作都用for循环解决,避免使用Arrays.asList
第二种方法
map.keySet().removeIf(v -> new ArrayList<Integer>(Arrays.asList(idsInt)).contains(v));
  • 还是使用Arrays.asList,但是转换成了java.util.ArrayList类来用

四、效率

long startTime = System.nanoTime();
// 代码(上面两种方法)
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("use:  " + duration / 1000000);
  • 设置2000000条map数据,idsInt = {2000,13000,57000,1000000},每种方法都跑三遍,发现:

    • for循环的最高时间为:270毫秒 且三次时间都在200~300毫秒内;
    • 集合Arrays.asList最高为369秒,300~400毫秒内。

所以建议使用for循环来做。OVER~~~~,搞完睡觉

一,项目环境

  • SpringBoot2.2.8
  • SpringSecurity
  • Gradle
  • Mysql
    随便一说:开发工具用Manjaro i3wm下的VSCode,有点香

二,数据库表字段及建表相关操作

  • 用户id,
  • 用户名,
  • 密码,
  • 手机号,
  • 账户锁定状态,
  • 用户使用状态,
  • 用户创建时间,
  • 用户最后登录时间
    (当前示例还没涉及用户权限相关内容哦,预告)

建库语句

CREATE DATABASE /*!32312 IF NOT EXISTS*/`fisha_demo` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;

建表语句

CREATE TABLE fisha_demo.fisha_user (
  `user_id` bigint(20) NOT NULL COMMENT '用户id,mybatis_plus雪花算法',
  `account` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '用户账号',
  `password` varchar(255) DEFAULT NULL COMMENT '用户加密密码',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号码(国际国内)',
  `locked` tinyint(2) DEFAULT '1' COMMENT '账户是否被锁定。1没被锁,2被锁(用户登录次数超出限制后会被锁定)',
  `deleted` tinyint(2) unsigned DEFAULT '1' COMMENT '账户状态。1正在使用,2被逻辑删除',
  `gmt_created` datetime DEFAULT NULL COMMENT '注册时间',
  `gmt_modified` datetime DEFAULT NULL COMMENT '最后活跃时间',
  PRIMARY KEY (`user_id`) COMMENT '主键索引'
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COMMENT='fisha用户实例表';

授权相关

项目使用的数据库用户密码为:java just1508,该用户拥有fisha_demo库所有的操作权限
create user 'java'@'localhost' identified by 'just1508'
grant all privileges on fisha_demo.* to 'java'@'localhost'

- 阅读剩余部分 -