Java第七篇:总结一些在项目常用的操作,包括一些开发注意点,说不定就有你要的。(java8)会持续更新!!!(2/4更新)

本篇文章将持续更新,汇总一些在实际开发中遇到的一些问题,希望能给有缘人一点帮助

List排序

  利用java8出来stream和lambda公式处理集合。
  场景一:需要根据List中Map的某个key-value值进行排序。

//这里有一个list
方式一:
List<Map<String,Object>> list;
//假如Map中有个字段orderNum是排序号,也就是我们需要根据这个orderNum值进行排序
//操作如下:
//先定义一个orderNum排序的

private static String comparingByOrderNum(Map<String,Object>){
	return map.get("orderNum") == null ? "" : map.get("orderNum").toString();
}
//排序,默认是升序排序
list = list.stream().sorted(Comparator.comparing(comparingByOrderNum所在的类名::comparingByOrderNum)).collect(Collectors.toList());
//倒序
list = list.stream().sorted(Comparator.comparing(comparingByOrderNum所在的类名::comparingByOrderNum).reversed()).collect(Collectors.toList());


方式二:利用lambda
list.sort((o1,o2) -> {
	Integer orderNumOne = (Integer)o1.get("orderNum");
	Integer orderNumTwo = (Integer)o2.get("orderNum");
	//倒序就交换orderNumOne和orderNumTwo的比较位置
	return orderNumOne.compareTo(orderNumTwo);
});

  场景二:需要根据实体中某个属性值进行排序。

//关于某个List<实体>的排序,建议直接将默认的排序方式写在获取list时的sql语句中,尽量不要在应用层排序,除非要修改排序方式。
//还是用stream方式排序,默认升序排序
list = list.stream().sorted(Comparator.comparing(实体的类名::getOrderNum)).collect(Collectors.toList());

构建通用的树形结构

  开发一些后端管理系统中经常会用到分类树形结构,或者分类下面加了该分类下的具体选项,比如空文件的文件夹的层级显示,以及另一种有文件情况下,每个文件在对应的文件夹中层级显示。下面两个场景可根据自己的需求结合成一个构建树型结构的帮助类。我这里只提供思路,因为很可能我写的方法不完全适合你,但是构建树的核心思想基本一致。况且明白了构建树型结构的核心思路,自己写一遍也会更加理解业务需求
  通常,如何判断哪个分类是另一个分类的子分类,都会在数据库定一个两个字段用来表示,这里我就用code,parentCode作为区分。
  场景三:只需要构建分类树型结果

//构建树的方式一般有两种,一是从最底层孩子结点往上遍历到根结点,二是从根结点往下遍历到最底层孩子结点,这看你需求,但两者原理一致可以互相转换。
//本文从根结点往下遍历到最底层孩子结点。
//思路如下:
//1.先获取需要进行构建树形结构的数据集(调用方法前)
List<实体类> tests= 获取该数据集的方法();

//2.再定义testLists用来接收将tests转换成List<Map<String, Object>>类型(调用方法前)
List<Map<String, Object>> testLists= Lists.newArrayList();

//3.转换方式如下,利用java8和fastjson的fluentPut方式:(调用方法前)
//本来tests中还有其他的字段属性,这里由于前端子需要这个几个,我就只取这几个字段,其他的看需求添加
tests.forEach(e -> testLists.add(new JSONObject()
                .fluentPut("id", e.getId())
                .fluentPut("name", e.getCatName())
                .fluentPut("code", e.getCode())
                .fluentPut("desc", e.getDesc())
                .fluentPut("parentCode", e.getParentCode())
                .fluentPut("orderNum", e.getOrderNum())));
                
//4.转换成List<Map<String, Object>>就可以开始调用构建树的方法,由于这里只需要构建树形结构,则调用我自己写的buildOnlyTreeFromParentToChild  
List<Map<String, Object>> resultList = buildTreeFromParentToChild(treeList,rootTag,selfTag,parentTag,additionalMap,addTag);

/*
* @param treeList 传入需要构建的实体list
* @param selfTag 树状关系表中表示当前层级的标签,例如id,code等
* @param parentTag 树状关系表中表示父母的标签,例如parent_id,parent_code等
* @param attrParams 定义要放在atributes中的参数
* @param removeParams  定义要移除显示的参数
* @return 返回完整的菜单树 
* @throws DataAccessException
*/ 
private static List<Map<String, Object>> buildOnlyTreeFromChildToParent(List<Map<String, Object>> treeList,String rootTag,String selfTag,String parentTag,List<String> attrParams,List<String> removeParams) throws DataAccessException {
		//定义好接受树形结构的类型,我这定义为List<Map<String,Object>>
        List<Map<String, Object>> rootList = new ArrayList<>();
        for (Map<String, Object> temp : treeList) {
            //根节点的parentTag,是否和当前的parentTag,默认为root值标志为根节点。并存入当前层级的rootList
            if (rootTag.equals(String.valueOf(temp.get(parentTag)))) {
                rootList.add(temp);
            }
        }
        //根据orderNum排序
        rootList = rootList.stream().sorted(Comparator.comparing(BuildTreeUtil::comparingByOrderNum)).collect(Collectors.toList());
		//递归调用自己,获取孩子之后,调用formateJson方法格式化节点信息
        for (Map<String, Object> temp : rootList) {
            List<Map<String, Object>> childs = buildOnlyTreeFromChildToParent(temp, treeList,selfTag,parentTag,attrParams,removeParams);
            formateJson(childs,temp,attrParams,removeParams);

        }
        return rootList;
    }

/*
* @param childs 传入childs列表,需要将childs放入当前结点key为childs的属性中
* @param temp 当前的节点信息
* @param attrParams 定义要放入temp节点key为atributes中的参数
* @param removeParams  定义要移除一些没必要显示的参数
* @throws DataAccessException
*/ 
private static void formateJson(List<Map<String, Object>> childs,Map<String, Object> temp,List<String> attrParams,List<String> removeParams){
		//判断是否有孩子,从而判断是否是叶子节点,前端可根据这个判断是否到底
        if(childs.size() > 0){
            temp.put("isLeaf" ,0);
        }else{
            temp.put("isLeaf" ,1);
        }
        //新增的uuid,避免显示数据库id
        String uuid =  new RandomGUID().toString();
        temp.put("uuid",uuid);
        //将孩子的列表放入这个key
        temp.put("childs", childs);
        //循环attrParams,添加到当前的attributes中
        Map<String, Object> attributes = Maps.newHashMap();
        if(attrParams.size() > 0){
            for(String param : attrParams){
                attributes.put(param,temp.get(param));
            }
        }
        temp.put("attributes", attributes);

        //清除前端不需要用的key-value
        for(String param : removeParams){
            temp.remove(param);
        }
    }

  场景四:不仅要构建分类树,还要将该分类下的数据放在对应的分类下面。比如我们按正常的文件夹目录存在文件夹和文件一样。

//树形结构中增加文件其实很简单,就是在分类每次添加到上一个分类的孩子中之前,先获取所属于上一个分类下的文件即可,一般文件属于哪个文件夹,都会有个标记字段,比如catId。但是得注意,由于分类和文件不一样的性质,所以需要跟场景三不同的处理方式
//这样就将上面的buildOnlyTreeFromChildToParent修改一下即可
//思路如下:
//1.先获取需要进行构建树形结构的数据集,一个是对应的分类数据集,另一个是文件数据集(调用方法前)
List<实体类> testCats= 获取该数据集的方法();
List<实体类> testFiles= 获取该数据集的方法();

//2.再定义testLists用来接收将tests转换成List<Map<String, Object>>类型(调用方法前)
List<Map<String, Object>> testCatLists= Lists.newArrayList();
List<Map<String, Object>> testFileLists= Lists.newArrayList();

//3.转换方式跟前面一样,利用java8和fastjson的fluentPut方式:(调用方法前)
//fileList中包含标记属于哪个cat的catId,但是如果catID为空,则表示他跟最顶层文件夹放在一起
testCatLists.forEach(e -> testLists.add(new JSONObject()
                .fluentPut("id", e.getId())
                .fluentPut("name", e.getCatName())
                .fluentPut("code", e.getCode())
                .fluentPut("desc", e.getDesc())
                .fluentPut("parentCode", e.getParentCode())
                .fluentPut("orderNum", e.getOrderNum())));
testFileLists.forEach(e -> testLists.add(new JSONObject()
                .fluentPut("id", e.getId())
                .fluentPut("name", e.getCatName())
                .fluentPut("catId", e.getCatId())
                .fluentPut("desc", e.getDesc())
                .fluentPut("orderNum", e.getOrderNum())));
                
//4.转换完成后调用buildTreeFromParentToChild
List<Map<String, Object>> resultLis = buildTreeFromParentToChild(testCatLists, "root", "code", "parentCode", testFileLists);

/*
* @param treeList 传入需要构建的实体分类catlist
* @param selfTag 树状关系表中表示当前层级的标签,例如id,code等
* @param parentTag 树状关系表中表示父母的标签,例如parent_id,parent_code等
* @param filesList 要跟分类绑定的文件列表
* @return 返回完整的菜单树 
* @throws DataAccessException
*/ 
private static List<Map<String, Object>> buildTreeByChildCode(Map<String, Object> tempTree, List<Map<String, Object>> treeList,List<Map<String, Object>> filesList ) throws DataAccessException {
        // 子菜单
        List<Map<String, Object>> tree = new ArrayList<>();
        for (Map<String, Object> temp : treeList) {
            // 遍历所有节点,判断父子关系
            if (String.valueOf(temp.get("parentCode")).equals(String.valueOf(tempTree.get("code")))) {
                tempTree.put("isLeaf",0);
                tree.add(temp);
            }
        }

        //根据排序号orderNum排序
        tree = tree.stream().sorted(Comparator.comparing(BuildTreeUtil::comparingByOrderNum)).collect(Collectors.toList());
        filesList = metaTabMapfilesList .stream().sorted(Comparator.comparing(BuildTreeUtil::comparingByOrderNum)).collect(Collectors.toList());

		//添加根节点资源表
        for(Map<String, Object> fileTemp : filesList ){
            //如果该资源的bizid为空,即无所属分类,放在根节点,否则就判断是当前分类下是否具有文件
            if ( fileTemp .get("catId") == null ){
            	//这里对file进行格式化处理
                rootList.add( initFileJson(fileTemp ));
            }else{
				if(fileTemp .get("catId").equals(fileTemp.get("id"))) {
                    rootList.add( initFileJson(fileTemp ));
                }
			}
        }
        //添加当前分类的孩子
        for (Map<String, Object> temp : rootList) {
        	if( temp.get("code") != null) {
            List<Map<String, Object>> childs = buildTreeByChildCode(temp, treeList, filesList );
            //格式化分类
            formateJson(childs,temp);
        }
          
        }
        return tree;
    }          

集合工具类的使用

  建议加入google.common.collect依赖,基本上组装了所有的集合类的所有操作方法。
  场景五:利用google.common.collect对各类集合的初始化

List<> list = Lists.newArrayList();
List<> list = Lists.newLinkedList();
Map<> map = Lists.newHashMap();
Map<> map = Lists.newLinkedHashMap();
...
//这里面有太多的方法可以使用,功能强大。
//创建一个集合类的空集合
//可以用java.util中的Collections
Collections.emptyList;
Collections.emptyMap;
....

开发中的性能问题建议

  • 应用层处理数据确实快,但也不能一次性获取太多的数据处理
    尽量不要一次性把数据取出来再在应用层过滤,很可能你一次性取出来的数据过大,导致响应速度过慢,甚至超过了内存限制,造成了堆栈溢出。
    建议:应用层每次取出来的数据尽量是一次处理的结果,另一次就重新再取一次,再结合在数据库的sql语句中增加过滤条件。
  • for循环中尽量不要出现访问数据库的操作
    for循环中尽量不要用getList(这是从数据库中获取一批数据的方法),这样也会造成性能问题。
    建议:这种情况很常见,数据量少是没有什么性能问题的,但是数据量一大,对数据库的压力很大。这个时候可以利用数据库的批量处理的sql语句来解决问题。具体情况综合考虑,不是非必要优化。
  • 如何避免两个for循环获取List中指定数据处理的情况
    这里我贴上另一篇文章的连接,比较详细。

开发中的可能遇到的一些小操作,但是不经常用又容易忘掉。

为了避免总是去百度和搜索,记录下自己在开发中遇到的一些不常用的小技巧,但是有可能用到的小操作。

// 获取指定date日志的年、月、日、时、分、秒
//如果要获取常用的日期组合,例如年-月-日、日-月-年等建议用DateFormat 
//举个例子,我只想获取date的时分秒
DateFormat dateFormat = DateFormat.getTimeInstance();
String format = dateFormat.format(date);
//只想获取年月日
DateFormat dateFormat = DateFormat.getDateInstance();
String format = dateFormat.format(date);
//获取完整的年月日时分秒
DateFormat dateFormat = DateFormat.getDateTimeInstance();
String format = dateFormat.format(date);

//但是如果你只想获取date中的某个数值,比如date的年份、月份、日等单个数据,建议用Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int year = cal.get(Calendar.YEAR);//获取年份  
int month=cal.get(Calendar.MONTH);//获取月份   
int day=cal.get(Calendar.DATE);//获取日   
int hour=cal.get(Calendar.HOUR);//小时   
int minute=cal.get(Calendar.MINUTE);//分              
int second=cal.get(Calendar.SECOND);//秒   
int WeekOfYear = cal.get(Calendar.DAY_OF_WEEK);//一周的第几天 

数据库知识

1.更新已有数据的表的字段属性
oracle是不允许直接更改的,需要进行如下操作

//先对表数据进行备份表
create table test_bak as select * from test;

 //再删除原来的表数据
delete from test;

 //修改表结构
alter table test modify field varchar2(100);

 //将备份表数据重插回原表中
insert into test select * from test_bak;

 //最后删除备份表。
drop table test;

//提交事务
 commit;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值