再谈编码规范

我曾经发过两篇文章阿里编码规范如何使用Java的注释,里面大致介绍了如何写注释,java代码编写的基本的约定等等,应该算是从事IT行业或者程序员的基本要求吧。可惜的是现在从事编程的门槛越来越低了,各种野路子出身的Coder简直逆天了。在你没有看到别人写的代码之前,你从来不会想象到怎么可以把代码写的这么"臭"!

下面我会贴一份完整的代码出来,请忽略它要实现的功能
后面我会讲到一系列的约定,约定即是规范,他虽然不是法则也不是公理或定理,但是你遵守了你才能跟世界更好的沟通

源代码:

package com.dtjx.controller.subWay;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import redis.clients.jedis.Jedis;

import com.dtjx.model.fault.Faulthistory;
import com.dtjx.model.route.Stop;
import com.dtjx.model.subWay.SubWayInfo;
import com.dtjx.model.systemset.SpecialFieldText;
import com.dtjx.model.systemset.Specialfield;
import com.dtjx.model.util.BigDataParam;
import com.dtjx.service.fault.FaulthistoryService;
import com.dtjx.service.route.StopService;
import com.dtjx.service.subWay.SubWayInfoService;
import com.dtjx.service.systemset.SpecialfieldService;
import com.dtjx.service.systemset.WebInterfaceService;
import com.dtjx.util.BigDataWebServiceInterfaceUtil;
import com.dtjx.util.MethodUtil;
import com.gph.saviorframework.quartz.SpringUtils;
import com.gph.saviorframework.shiro.session.RedisManager;

/*class MyThread implements Runnable{ private Map<Integer,Object> subwayLifeCount=new HashMap<Integer,Object>(); private Jedis redis=SpringUtils.getBean(RedisManager.class).getJedis();; public MyThread() { //this.name = name; } public void run(){ for(int i=0;i<100;i++){ //System.out.println("线程开始:"+this.name+",i="+i); } }*/
public class DrivingStateMonitorThread{  
private Map<Integer,Object> subwayLifeCount=new HashMap<Integer,Object>();
private Jedis redis=SpringUtils.getBean(RedisManager.class).getJedis();
private StopService stopService=SpringUtils.getBean(StopService.class);
class subWayStatusCount{
	 private int subWayOnline;
	 private int subWayOffline;
	 private int subWayOnFault;
	public int getSubWayOnline() {
		return subWayOnline;
	}
	public void setSubWayOnline(int subWayOnline) {
		this.subWayOnline = subWayOnline;
	}
	public int getSubWayOffline() {
		return subWayOffline;
	}
	public void setSubWayOffline(int subWayOffline) {
		this.subWayOffline = subWayOffline;
	}
	public int getSubWayOnFault() {
		return subWayOnFault;
	}
	public void setSubWayOnFault(int subWayOnFault) {
		this.subWayOnFault = subWayOnFault;
	}
	 
}
public class SubWayDrivingStatus extends SubWayInfo{
	private String runningModel="--";//运行模式
	private String speed="0";//速度
	private String endStopId="1";//终点站Id
	private String nowStopId="0";//当前站Id
	private String nextStopId="1";//下一站Id
	private String endStop="--";//终点站
	private String nowStop="--";//当前站
	private String nextStop="--";//下一站
	private String driverNumber;//司机工号
	private String drivingStatus;//运行状态 低速/高速/正常/停止
	private String faults="无故障";//列车故障
	private String updateTime;//更新时间
	private String bogieStatus="正常";//转向架状态
	private String workingCondition="--";//工况
	private String nextStopDistance="--";//下一站距离
	//构造函数
	public SubWayDrivingStatus(){
		
	};
    public SubWayDrivingStatus(SubWayInfo s){
    	super(s.getId(), s.getSubwayNum(), s.getSubwayCarriageNum(), 
    			s.getSubwayInfomation(), s.getCitys(),s.getCityName(), s.getRouteId(),
				s.getRouteName(), s.getSubwayStatus(), s.getIsDeleted());
	};
	public String getEndStopId() {
		return endStopId;
	}
	public void setEndStopId(String endStopId) {
		this.endStopId = endStopId;
	}
	public String getNowStopId() {
		return nowStopId;
	}
	public void setNowStopId(String nowStopId) {
		this.nowStopId = nowStopId;
	}
	public String getNextStopId() {
		return nextStopId;
	}
	public void setNextStopId(String nextStopId) {
		this.nextStopId = nextStopId;
	}
	public String getNextStopDistance() {
		return nextStopDistance;
	}
	public void setNextStopDistance(String nextStopDistance) {
		this.nextStopDistance = nextStopDistance;
	}
	public String getRunningModel() {
		return runningModel;
	}
	public String getSpeed() {
		return speed;
	}
	public void setSpeed(String speed) {
		this.speed = speed;
	}
	public void setRunningModel(String runningModel) {
		this.runningModel = runningModel;
	}
	public String getEndStop() {
		return endStop;
	}
	public String getNowStop() {
		return nowStop;
	}
	public String getNextStop() {
		return nextStop;
	}
	public String getDriverNumber() {
		return driverNumber;
	}
	public void setDriverNumber(String driverNumber) {
		this.driverNumber = driverNumber;
	}
	public String getDrivingStatus() {
		return drivingStatus;
	}
	public void setDrivingStatus(String drivingStatus) {
		this.drivingStatus = drivingStatus;
	}
	public String getFaults() {
		return faults;
	}
	public void setFaults(String faults) {
		this.faults = faults;
	}
	public String getUpdateTime() {
		return updateTime;
	}
	public void setUpdateTime(String updateTime) {
		this.updateTime = updateTime;
	}
	public String getWorkingCondition() {
		return workingCondition;
	}
	public void setWorkingCondition(String workingCondition) {
		this.workingCondition = workingCondition;
	}
	public String getBogieStatus() {
		return bogieStatus;
	}
	public void setBogieStatus(String bogieStatus) {
		this.bogieStatus = bogieStatus;
	}
}
public List getSubwayListAll()
{
	List subwayListAll =null;
	//首先判断redis中是否是列车信息的全部列表
	String subWayInfoAll=redis.get("subWayInfo-all");
	if(subWayInfoAll == null || subWayInfoAll.trim().isEmpty())
	{
		SubWayInfoService subWayInfoService=SpringUtils.getBean(SubWayInfoService.class);
		Map<String, Object> params =new HashMap<String, Object>();
		params.put("sort", "id");
		params.put("dir", "desc");
		subwayListAll = subWayInfoService.findSubWayInfo(params);//全部的列车信息
		redis.set("subWayInfo-all", JSONArray.fromObject(subwayListAll).toString());
	}
	else
	{
		subwayListAll=JSONArray.toList(JSONArray.fromObject(subWayInfoAll),SubWayInfo.class);
		//subwayListAll=(List) JSONUtils.parse(subWayInfoAll);
	}
	return subwayListAll;
}

   /** * 获取所有列车的形式状态信息,并定时更新 * 逻辑:查询数据库中现有的车辆信息,然后根据遍历车辆信息,取列车编号去查询大数据端,获取大数据端的数据, * 进行数据拼接 * 返回内容:返回的数据内容是 车辆的基本信息+大数据端的车辆行驶信息 * @return */
	public void getlist() {
		SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//System.out.println("列车行驶状态监测启动"+formatShow.format(new Date()));
		Integer subWayCount = 0;// 列车总量
		subWayStatusCount ssc=new subWayStatusCount();
		ssc.setSubWayOffline(0);// 离线列车的数量
		ssc.setSubWayOnFault(0);// 故障列车的数量
		ssc.setSubWayOnline(0);// 在线列车的数量
		
		try {
			SpecialfieldService specialfieldservice=SpringUtils.getBean(SpecialfieldService.class);
			WebInterfaceService webInterfaceservice=SpringUtils.getBean(WebInterfaceService.class);
			List subwayListAll =getSubwayListAll();
			String dataTime="2017010100000000";
			subWayCount = subwayListAll.size();
			/**将for循环中需要的变量提前定义,再循环体内赋值指定,不再新建,可提升性能**/
			List statusList = new ArrayList();
			Specialfield sf = new Specialfield();
			SubWayInfo m =null;
			BigDataParam bigParam=new BigDataParam();//大数据接口所需的参数
			for (int i = 0; i < subwayListAll.size(); i++) {
				m = (SubWayInfo) subwayListAll.get(i);
					if(!subwayLifeCount.containsKey(m.getId()))
					{
						Map<String,Object> indexMap=new HashMap<String,Object>();
						indexMap.put("lifeSignl", "");//生命信号
						indexMap.put("count",0);//生命信号重复的次数
						subwayLifeCount.put(m.getId(), indexMap);
					}
					SubWayDrivingStatus sds = initSubWayDrivingStatus(m);
					/*获取大数据端接口参数*/
					bigParam.initBySubwayInfo(m);
					/*获取特殊字段列表*/
					sf.setCitys(m.getCitys());
					sf.setRoutes(m.getRouteId());
					List<Specialfield> specialfieldList = specialfieldservice.get(sf);
					List<Map<String,Object>> specialfieldGroup=specialfieldservice.getSpecialfieldGroupByTrainumInterfacenum(sf);
					List<String> list=new ArrayList<String>();
					for(int j=0;j<specialfieldGroup.size();j++)
					{
						Map<String, Object> mc=specialfieldGroup.get(j);
						bigParam.setData_code(String.valueOf(mc.get("datacoding")).split(","));
						bigParam.setData_type(String.valueOf(mc.get("datatype")).split(","));
						bigParam.setImetro_car_no(String.valueOf(mc.get("trainum")));
						bigParam.setIpackage(mc.get("interfacenum").toString());
						//list.addAll(BigDataWebServiceInterfaceUtil.getRealTimeDataFromFile(webInterfaceservice,bigParam));
						list.addAll(BigDataWebServiceInterfaceUtil.getRealTimeData(webInterfaceservice,bigParam));
					}
					if(list.size()<=0)
					{
						sds.setSubwayStatus("离线");;
					}
					else
					{
						if(!specialfieldList.isEmpty())
						{
							Specialfield s=null;
							for (int j=0;j<specialfieldList.size();j++) {
								s=specialfieldList.get(j);
								Field field;
								String itemValue=s.getItemvalue();
								String itemName=s.getItemname();
								String dataCoding=s.getDatacoding();
								try {
									field = sds.getClass().getDeclaredField(itemValue);
									field.setAccessible(true);
									
									for(int r=0;r<list.size();r++)
									{
										String str=list.get(r);
										if (str!=null && !str.isEmpty()) {
											//field.set(sds, "0");
											JSONObject json2 = JSONObject.fromObject(str);
											for (Iterator iter = json2.keys(); iter.hasNext();) {
												String key = (String)iter.next();
												JSONObject json=JSONObject.fromObject(json2.getString(key));
												if(!json.isNullObject()&&!json.isEmpty())
												{
													if(json.containsKey("OP_TIME"))
													{
														dataTime=json.getString("OP_TIME");
													}
													if (json.containsKey(dataCoding)) {
														field.set(sds, json.get(dataCoding).toString());
														if (itemName.equalsIgnoreCase("速度")) {
															sds.setDrivingStatus(MethodUtil.subwayStatusBySpeed(Double.valueOf(json.get(dataCoding).toString())));
														}
														else if (itemName.equalsIgnoreCase("生命信号")) {
															
															String signl=json.get(dataCoding).toString();
															writeLifeMap(signl,m.getId());
														}
														else if (itemName.equalsIgnoreCase("工况")||itemName.equalsIgnoreCase("模式")) {
															String value=json.get(dataCoding).toString();
															List<SpecialFieldText> sptList = s.getShowArr();
															specialCodeShowValue(sptList,value,itemName,sds);
														}
													}
												}
												else
												{
													continue;
												}
													 
											}
									}
									}
								} catch (Exception e) {
									// TODO Auto-generated catch block
									//e.printStackTrace();
									continue;
								}
									
							}
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
						else
						{
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
					}
					
					statusList.add(sds);
			}
			redis.set("DrivingState", JSONArray.fromObject(statusList).toString());
			redis.set("DrivingState-subWayCount", subWayCount.toString());
			redis.set("DrivingState-subWayOnline", String.valueOf(ssc.getSubWayOnline()));
			redis.set("DrivingState-subWayOffline",String.valueOf(ssc.getSubWayOffline()));
			redis.set("DrivingState-subWayOnFault",String.valueOf(ssc.getSubWayOnFault()));
			if (redis != null) {
				redis.close();
	        }
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public SubWayDrivingStatus initSubWayDrivingStatus(SubWayInfo s)
	{
		SubWayDrivingStatus sds=new SubWayDrivingStatus(s);
		return sds;
	}
	//根据生命信号的变化,对各个列车的生命信号重复的计数进行读取和改写
	public void writeLifeMap(String signl,Integer id)	{
		Map lifeMap=(Map) subwayLifeCount.get(id);
		if(signl.equalsIgnoreCase(lifeMap.get("lifeSignl").toString()))
		{
			int c=(int)lifeMap.get("count");
			lifeMap.put("count", c+1);												}
		else
		{
			lifeMap.put("lifeSignl",signl);
			lifeMap.put("count", 0);
		}
	
	}
	//根据生命信号的变化,对各个列车的生命信号重复的计数进行读取和改写
		public Integer getLifeCount(Integer id)	{
			int c=0;
			try {
				Map lifeMap=(Map) subwayLifeCount.get(id);
				c=(int)lifeMap.get("count");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return c;
				
		
		}
	//将需要key-vaue对应的字段进行特殊的处理
	public void specialCodeShowValue(List<SpecialFieldText> sptList,String value,String itemname,SubWayDrivingStatus sds)
	{
		for (int j = 0; j < sptList.size(); j++) {
			SpecialFieldText spt = sptList.get(j);
			if (spt.getValue().equals(Integer.valueOf(value).toString())) {
				if(itemname.equalsIgnoreCase("工况"))
				{
					sds.setWorkingCondition(spt.getText());
					break;//找到了,退出当前循环
				}
				else if(itemname.equalsIgnoreCase("模式"))
				{
					sds.setRunningModel(spt.getText());
					break;//找到了,退出当前循环
					}
			}
		}
	}

/** * 根据数据时间来判定车辆是离线还是在线 * @param dataTime * @param sds * @param trainId * @param ssc */
	/** * 诊断车辆的状态,根据是生命信号,如果生命信号连续10次都一样,则判定为离线,如果少于10次则为在线 * @param count 生命信号重复的次数 * @param dataTime 数据时间 * @param sds 列车行驶状态实体 * @param trainId 列车id * @param ssc 列车状态 */
	public void setSubWayStatus(Integer count, String dataTime,SubWayDrivingStatus sds,
			Integer trainId, subWayStatusCount ssc) {
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			int subWayOnline=ssc.getSubWayOnline();
			int subWayOnFault=ssc.getSubWayOnFault();
			int subWayOffline=ssc.getSubWayOffline();
			Date date1 = format.parse(dataTime);
			if (count<10)//小于10次相同的生命信号,代表车辆还在线
			{

				sds.setSubwayStatus("在线");
				subWayOnline++;
				String faultResult = haveFault(trainId);
				sds.setFaults(faultResult);
				if (!faultResult.equals("无故障")) {
					subWayOnFault++;
					sds.setFaults("有故障");
					if(faultResult.equals("有转向架故障"))
					{
						sds.setBogieStatus("故障");
					}
					else
					{
						sds.setBogieStatus("正常");
					}
				}

			} else {// 如果生命信号连续10次相同,则代表 本列车已经离线
					sds.setSubwayStatus("离线");
					sds.setDrivingStatus("");
					subWayOffline++;
					String faultResult = haveFault(trainId);
					sds.setFaults(faultResult);
					if (!faultResult.equals("无故障")) {
						subWayOnFault++;
						sds.setFaults("有故障");
						if(faultResult.equals("有转向架故障"))
						{
							sds.setBogieStatus("故障");
						}
						else
						{
							sds.setBogieStatus("正常");
						}
						
					}
		
			}
			Stop stop=new Stop();
			stop=stopService.selectByActualId(sds.getEndStopId(),sds.getRouteId(),sds.getCitys());
			if(stop!=null)
			{
				sds.endStop=stop.getStopName();
			}
			else
			{
				sds.endStop="--";
			}
			stop=stopService.selectByActualId(sds.getNowStopId(),sds.getRouteId(),sds.getCitys());
			if(stop!=null)
			{
				sds.nowStop=stop.getStopName();
			}
			else
			{
				sds.nowStop="--";
			}
			stop=stopService.selectByActualId(sds.getNextStopId(),sds.getRouteId(),sds.getCitys());
			if(stop!=null)
			{
				sds.nextStop=stop.getStopName();
			}
			else
			{
				sds.nextStop="--";
			}
			stop=null;
			sds.setUpdateTime(formatShow.format(date1));
			ssc.setSubWayOffline(subWayOffline);// 离线列车的数量
			ssc.setSubWayOnFault(subWayOnFault);// 故障列车的数量
			ssc.setSubWayOnline(subWayOnline);// 在线列车的数量
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/** * 判断是否有故障 * @param trainId * @return */
	public String haveFault(Integer trainId) {
		Faulthistory f = new Faulthistory();
		f.setTrainid(trainId.toString());
		FaulthistoryService faulthistoryservice=SpringUtils.getBean(FaulthistoryService.class);
		List<Faulthistory> list = faulthistoryservice.get(f);
		boolean flag = false;
		String result="无故障";
		for (Faulthistory ft : list) {
			if (ft.getFaultstatus().equals("1")) {
				flag = true;
				result= "有故障";
				if(ft.getSystems().equals("575"))//如果是转向架的问题
				{
					result= "有转向架故障";
				}
			}
		}
		faulthistoryservice=null;
		//return (flag? "有故障" : "无故障");
		return result;

	}
	public List<Map<String, Object>>  groupListByCarNo( List<Specialfield> dataList)
	{
		List<Map<String, Object>> listMapResult=new ArrayList<Map<String, Object>>();
		Specialfield dataItem=new Specialfield(); // 数据库中查询到的每条记录
		Map<String, List<Specialfield>> resultMap= new HashMap<String, List<Specialfield>>(); // 最终要的结果
		for(int i=0;i<dataList.size();i++){
		    dataItem = dataList.get(i);
		    if(resultMap.containsKey(dataItem.getTrainum())){
		        resultMap.get(dataItem.getTrainum()).add(dataItem);
		    }else{
		        List<Specialfield> list = new ArrayList<Specialfield>();
		        list.add(dataItem);
		        resultMap.put(dataItem.getTrainum(),list);
		    }
		} 
		
		Iterator it=resultMap.keySet().iterator();
		while(it.hasNext())
		{
			Map<String, Object> m=new HashMap<String, Object>();
			String key=it.next().toString();
			List<Specialfield> L=resultMap.get(key);
			m.put("carNo", key);
			m.put("fields", L);
			listMapResult.add(m);
		}

		return listMapResult;
			
		}
};

上面是一个完整的类文件,然后从头到尾分析这个类文件的编码规范性,以及开发的基本要求。

看类文件整体

首先,作为程序员,写完一段代码后,要把代码格式化一下,并且做这一步非常简单。目前,据我了解市面上所有的IDE工具,都带有格式化功能,可以对某一段/块代码,某个类文件,甚至对所有类文件(整个项目)整体格式化。相信可能有某些个别‘异类’就喜欢用记事本这个编辑软件,写代码就用它,即便是这样,那你也应该手动的格式化你的代码!这是最基本的要求!

接着看上面代码,公司要求用eclipse开发,结果代码写完了,显然没有格式化:类和属性,该缩进的不缩,不该缩进的缩进,变量/属性对不齐…乱七八糟的
在这里插入图片描述

上面贴图的这段代码,远不止图中所说的这些问题

内部类的约定

在java中使用内部类/静态内部类/私有静态内部类,请遵守约定,要放到主类的最后面,或者至少要放到主类里公开方法的后面,多阅读一下java的原码,大神的代码总是需要你去借鉴的,从来没有发现主类定义好了,紧接着定义内部类,他们总是在主类的后面

关于类的注释

对于一个类文件(一个类文件可能包含多个类)或者一个类,在主类上必须包含类注释,并且注释的格式必须用如下的格式

/** * ... * / 

不允许使用 // ... 或者 /*...*/ 格式,这里说一下原因,一个类完成后,在生成java api时候,只识别 /** ... */ 格式的注释,不识别后面两种注释。

另外再说明一下,类注释中需要说明类的主要作用,作者,版本等,可参考 javadoc注释标签 另外在注释中是支持html标签的

关于类、属性的注释约定

在使用publicprotected修饰的类和属性必须提供注释说明,并且采用/** ... */ 格式的注释

特别是public 修饰符,在生成java api的时候是一定会对其生成api的,如果不注释,即便生成了api,你也不知道它是做什么的!

上面贴图中,所有的public的方法,都没有注释,这是不符合规范的;图中getter和setter方法都缺少注释

去掉无效的注释

虽然不写注释,会让人感觉很可恶 ,但这不是最可恶的,最可恶的是对代码理解没有完全作用甚至还恶意误导别人理解你得意思的注释,这样的注释需要在你的代码中坚决剔除掉!
在这里插入图片描述
上面这一块代码删掉吧,既不是对类的注释,读一下,还容易误导他人要起线程去跑什么东西;仔细看看还跟这个类没任何一点儿关系,这不是在浪费别人的时间吗?

公共类请分别定义成两个类文件,不要放到一起

在这里插入图片描述
没有什么好说的,上面贴图主类是DrivingStateMonitorThread,紧接着有定义了一个公共类SubWayDrivingStatus,请把SubWayDrivingStatus单独定义一个类文件,或者去掉public修饰符。

我们再看这个内部类SubWayDrivingStatus的两个构造函数定义
在这里插入图片描述
写过多年java代码,头一次看到这样定义构造函数的,方法后加分号,虽然写分号不报错,我感觉应该给IDE打差评;分号不该写的地方,不要随便乱写!

java的另一个规范用法:大括号的使用

在这里插入图片描述

看了上面贴图的代码,我的第一印象,这是个一写C语言代码的孩子转来写java的;还别说,仔细看看还挺“优美”的,用大括号结构对称啊!

但是,java代码有java自己的规范,首先使用大括号的结构请保持如下结构:
Eclipse里面就有java代码格式

java泛型的使用

接着看代码,函数public List getSubwayListAll()的返回类型是List,而List是一个接口,代表某类数据的集合,既然是某类数据,那么这个某类就可以代表任何数据啦,比如说,一个int数字,一个String字符串,一个Double的双精度小数,获取其他什么的类型的java对象,这个List都能放的下,现在问题就有了,既然返回是这个List数据,调用这个方法getSubwayListAll()的人怎么可能知道你到底在List里面放的是什么数据呢!

java泛型从jdk5就已经引入了,现在都出来jdk10了,代码里面还出现这么低级的类型错误,这玩意的隐患太多了,请添加上泛型用于说明给调用人的是何种数据,请写public List<SubWayInfo> getSubwayListAll(){...}

如何写好让别人懂的代码

接着往下看,这就来到了,最让人费解的代码之处了

/** * 获取所有列车的形式状态信息,并定时更新 * 逻辑:查询数据库中现有的车辆信息,然后根据遍历车辆信息,取列车编号去查询大数据端,获取大数据端的数据, * 进行数据拼接 * 返回内容:返回的数据内容是 车辆的基本信息+大数据端的车辆行驶信息 * @return */
	public void getlist() {
		SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//System.out.println("列车行驶状态监测启动"+formatShow.format(new Date()));
		Integer subWayCount = 0;// 列车总量
		subWayStatusCount ssc=new subWayStatusCount();
		ssc.setSubWayOffline(0);// 离线列车的数量
		ssc.setSubWayOnFault(0);// 故障列车的数量
		ssc.setSubWayOnline(0);// 在线列车的数量
		
		try {
			SpecialfieldService specialfieldservice=SpringUtils.getBean(SpecialfieldService.class);
			WebInterfaceService webInterfaceservice=SpringUtils.getBean(WebInterfaceService.class);
			List subwayListAll =getSubwayListAll();
			String dataTime="2017010100000000";
			subWayCount = subwayListAll.size();
			/**将for循环中需要的变量提前定义,再循环体内赋值指定,不再新建,可提升性能**/
			List statusList = new ArrayList();
			Specialfield sf = new Specialfield();
			SubWayInfo m =null;
			BigDataParam bigParam=new BigDataParam();//大数据接口所需的参数
			for (int i = 0; i < subwayListAll.size(); i++) {
				m = (SubWayInfo) subwayListAll.get(i);
					if(!subwayLifeCount.containsKey(m.getId()))
					{
						Map<String,Object> indexMap=new HashMap<String,Object>();
						indexMap.put("lifeSignl", "");//生命信号
						indexMap.put("count",0);//生命信号重复的次数
						subwayLifeCount.put(m.getId(), indexMap);
					}
					SubWayDrivingStatus sds = initSubWayDrivingStatus(m);
					/*获取大数据端接口参数*/
					bigParam.initBySubwayInfo(m);
					/*获取特殊字段列表*/
					sf.setCitys(m.getCitys());
					sf.setRoutes(m.getRouteId());
					List<Specialfield> specialfieldList = specialfieldservice.get(sf);
					List<Map<String,Object>> specialfieldGroup=specialfieldservice.
							getSpecialfieldGroupByTrainumInterfacenum(sf);
					List<String> list=new ArrayList<String>();
					for(int j=0;j<specialfieldGroup.size();j++)
					{
						Map<String, Object> mc=specialfieldGroup.get(j);
						bigParam.setData_code(String.valueOf(mc.get("datacoding")).split(","));
						bigParam.setData_type(String.valueOf(mc.get("datatype")).split(","));
						bigParam.setImetro_car_no(String.valueOf(mc.get("trainum")));
						bigParam.setIpackage(mc.get("interfacenum").toString());
						//list.addAll(BigDataWebServiceInterfaceUtil.
						// getRealTimeDataFromFile(webInterfaceservice,bigParam));
						list.addAll(BigDataWebServiceInterfaceUtil.
								getRealTimeData(webInterfaceservice,bigParam));
					}
					if(list.size()<=0)
					{
						sds.setSubwayStatus("离线");;
					}
					else
					{
						if(!specialfieldList.isEmpty())
						{
							Specialfield s=null;
							for (int j=0;j<specialfieldList.size();j++) {
								s=specialfieldList.get(j);
								Field field;
								String itemValue=s.getItemvalue();
								String itemName=s.getItemname();
								String dataCoding=s.getDatacoding();
								try {
									field = sds.getClass().getDeclaredField(itemValue);
									field.setAccessible(true);
									
									for(int r=0;r<list.size();r++)
									{
										String str=list.get(r);
										if (str!=null && !str.isEmpty()) {
											//field.set(sds, "0");
											JSONObject json2 = JSONObject.fromObject(str);
											for (Iterator iter = json2.keys(); iter.hasNext();) {
												String key = (String)iter.next();
												JSONObject json=JSONObject.fromObject(json2.getString(key));
												if(!json.isNullObject()&&!json.isEmpty())
												{
													if(json.containsKey("OP_TIME"))
													{
														dataTime=json.getString("OP_TIME");
													}
													if (json.containsKey(dataCoding)) {
														field.set(sds, json.get(dataCoding).toString());
														if (itemName.equalsIgnoreCase("速度")) {
															sds.setDrivingStatus(MethodUtil.subwayStatusBySpeed(Double.valueOf(json.get(dataCoding).toString())));
														}
														else if (itemName.equalsIgnoreCase("生命信号")) {
															
															String signl=json.get(dataCoding).toString();
															writeLifeMap(signl,m.getId());
														}
														else if (itemName.equalsIgnoreCase("工况")||itemName.equalsIgnoreCase("模式")) {
															String value=json.get(dataCoding).toString();
															List<SpecialFieldText> sptList = s.getShowArr();
															specialCodeShowValue(sptList,value,itemName,sds);
														}
													}
												}
												else
												{
													continue;
												}
													 
											}
									}
									}
								} catch (Exception e) {
									// TODO Auto-generated catch block
									//e.printStackTrace();
									continue;
								}
									
							}
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
						else
						{
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
					}
					
					statusList.add(sds);
			}
			redis.set("DrivingState", JSONArray.fromObject(statusList).toString());
			redis.set("DrivingState-subWayCount", subWayCount.toString());
			redis.set("DrivingState-subWayOnline", String.valueOf(ssc.getSubWayOnline()));
			redis.set("DrivingState-subWayOffline",String.valueOf(ssc.getSubWayOffline()));
			redis.set("DrivingState-subWayOnFault",String.valueOf(ssc.getSubWayOnFault()));
			if (redis != null) {
				redis.close();
	        }
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

这段代码总共有148行,初看一下感觉并不复杂,毕竟还有注释解析方法功能,再一细读,简直天堂地狱可远观而不可亵玩焉奈何小生没文化,一句‘卧槽’行天下

也更加验证了,这孩子是写C语言的,绝对不适合面向对象编程,一溜到底,由上而下,我是读了一遍又一遍勉勉强强马马虎虎还是不敢说知道它到底要干什么?真是防**找这样的程序员写代码在合适不过了!

我先把代码中明显的问题找一遍,然后在分析我也不知道对不对的问题

void方法,注释不应该加@return

因为这个方法已经是void的,他就没返回值,所以注释中不应该出现@return

方法中无关紧要的变量不应该出现

代码中第一行就有 SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 这行对代码没任何意义,可能测试的是候用到这个时间,因为下一行注释了一个打印日期的代码,既然打印的都注释了,为什么第一行不一起注释掉呢?

在这里插入图片描述
另外,泛型问题,参考前面讨论

方法内部注释

在方法内部,使用注释因为其不会生成javadoc所以只需采用 // .../* ... */ 即可

学会使用TODO、FIXME、XXX等特殊注释

在这里插入图片描述
上面这块代码中已经处理完了异常时候要继续工作,就不应该TODO了,直接删掉不能保留

以上就是这148行代码,打眼一看就能发现的问题,然后在从上到下,看一遍,还会发现另一个严重问题

一个java方法中,不论判断语句还是循环语句,禁止嵌套3层以上

在看看这个代码,for循环就已经4层嵌套了,更不用说里面还有if-else嵌套,这样一堆代码堆在一起只能让人更加迷糊,且不说对不对吧,测试都不好下手,为你这个方法,需要准备多少测试用例啊?这还是能看到代码的情况下,要是黑盒测,这段代码的隐患的多大!!!

直到现在我也不想弄懂上面代码的处理过程,我要说的是如果遇到这种复杂的处理过程,我们应该怎么做:

一个方法应尽可能的简单

我们总是希望一个方法越简单越好,最好的方法就是只做一件事情!

使用包装可以减少业务逻辑的复杂度

比如说上面代码中4层for嵌套,可以考虑设计三个方法,分别用于包含一套for循环,使其尽量“看起来”不那么复杂;

通用数据结构,就用类包装起来;

代码中需要区分public还是private

在这里插入图片描述
上面代码是用于判断列车是否有故障,它是服务于getlist()方法,其他任何地方都不会在调用它,那么这里方法的类型用public修饰就是不合适的,应该当改成private的作为类内部的私有方法,代码中所有的方法都定义成了public的,这是不应该的

包,类,方法,属性命名原则

  1. 包名的书写规范 (Package) 推荐使用公司或机构的顶级域名为包名的前缀,目的是保证各公司/机构内所使用的包名的唯一性。包名全部为小写字母,且具有实际的区分意义。
  2. 类名的书写规范 (Class) 类名必须使用名词,如果一个类名内含多个单词,那么各个单词第一个字母大写,后续字母小写,起伏呈驼峰状,人称驼峰式命名。
  3. 驼峰命名法(Camel-Case): 当变量名或函式名是由一个或多个单字连结在一起,而构成的唯一识别字时,首字母以小写开头,每个单词首字母大写(第一个单词除外)。

特殊注释说明

在一些IDE中规定的特殊注释,例如eclipse中就内置了TODO,FIXME,XXX特殊注释,同时也可以自定义一些注释

注释 说明
TODO 表示需要实现,但目前还未实现的功能
FIXME 代码是错误的,不能工作,需要修复
XXX 勉强可以工作,但是性能差等原因

这些特殊注释放到代码中,用于提醒编码人员注意和查找,如下是eclipse的特殊注释展示效果
eclipse特殊注释
另外在Eclipse的Markers标签下也会查找到所有特殊注释
在这里插入图片描述

javadoc注释标签

标签 说明
@author 标明开发该类模块的作者,可以多次使用,以指明多个作者
@version 标明该类模块的版本,也可以使用多次,只有第一次有效
@see 参考转向,也就是相关主题 @see 类名 @see 完整类名 @see 完整类名#方法名,生成参考其他的JavaDoc文档的连接
@param 对方法中某参数的说明,使用在方法中,也可以用于类上
@return 对方法返回值的说明,使用在方法中
@exception 对方法可能抛出的异常进行说明 ,使用在方法中
@since 指定最早出现在哪个版本,跟@version有关系
@serial 说明一个序列化属性
@serialData 说明通过writeObject( ) 和 writeExternal( )方法写的数据
@serialField 说明一个ObjectStreamField组件
@deprecated 由于某种原因而被宣布将要被废弃的方法。
{@docRoot} 指明当前文档根目录的路径
{@inheritDoc} 从直接父类继承的注释
{@linkplain #function name} 链接,插入一个到另一个主题的链接,但是该链接显示纯文本字体
{@link #function name} 链接,生成参考其他的JavaDoc文档,它和@see标记的区别在于,@link标记能够嵌入到注释语句中,为注释语句中的特殊词汇生成连接。 eg.{@link Hello}
{@value} 显示常量的值,该常量必须是static属性
{@code} 相当于添加<code></code>,表名里面的是代码
{@literal} 忽略掉标签解析

结语

不论你是学生还是已经在公司工作了,请认真对待你得代码。