JavaBlog2
一、前言
本次博客文章主要是关于java课程第二阶段关于PTA题目集、超星作业以及期中考试的总结。相较于第一阶段的作业总结而言此次作业更加针对于总结在面向对象过程中的三大技术特性,即封装性、继承性和多态性,以及相关一些面向对象设计过程中的一些基本原则的理解和分析此阶段作业中出现的问题和与之对应的解决方法,这个阶段的题目相对于第一阶段难度大大增加,经常会到一种无从下手的地步,难度也随着这三大技术的进阶而逐渐进阶。最后在总结这一阶段众多方面的教训以及收获。
二、设计与分析
题目集4:菜单计价程序-3
菜单计价的思路是通过构建类对象来完成主函数中的一系列问题,通过对键盘输入的菜单和table信息和点单信息进行计算输出,其中使用正则表达式能够简化大量判断代码,首先这道题的数组假设换成Arralist能够起到要用时创建,不会造成空间浪费相关问题,而且Arralist有很多API方法能够直接使用,这个题目的难点还有对于时间的折扣要进行考虑,而且在日期中个某个方法中的星期与我们认知的不同需要转化。除此之外在于一些不符合输入规范的内容需要进行相应的输出。代码如下:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input=new Scanner(System.in); String []menu =new String[500]; int []price=new int[500]; String menuName; int inputPrice; int i=0; String wholeJudge; while(true) { int reption=1; menuName=input.next(); if(menuName.equals("1")) { wholeJudge="1"; break; } if(menuName.equals("end")) { wholeJudge="0"; break; } inputPrice=input.nextInt(); for(int k=0;k<i;k++) if(menuName.equals(menu[k])) { price[k]=inputPrice;reption=0; break; } if(reption==1) { menu[i]=menuName; price[i]=inputPrice; i++; } } int everyPrice=0; int totalPrice = 0; int count=0; int []recording=new int[100]; int re=0; int judge3=1,judge2=0; String endJudge=""; if(wholeJudge.equals("1")) while(!wholeJudge.equals("end")) { everyPrice=0; int flag=0; String order=input.next(); if(order.equals("delete")) { if(judge2==1&&judge3==0) wholeJudge = endJudge; int p=Integer.parseInt(wholeJudge); if(p<1||p>count||recording[p-1]==0) System.out.println("delete error;"); if(p>=1&&p<=count&&recording[p-1]!=0) { totalPrice -= recording[p-1]; recording[p-1]=0; } endJudge = input.next(); judge3 = 0; if(endJudge.equals("end")) break; else { judge2=1; wholeJudge=endJudge; continue; } } else judge3=1; int size1=input.nextInt(); int b=input.nextInt(); for(int j=0;j<i;j++) { if(order.equals(menu[j])) { flag=1; if(size1==1)everyPrice+=price[j]; if(size1==2) { if(price[j]%2==1) everyPrice+=price[j]*1.5+1; else everyPrice+=price[j]*1.5; } if(size1==3) everyPrice+=2*price[j]; } } if(flag==0) { recording[re++]=0; System.out.println(order+" does not exist"); count++; } if(flag==1) { everyPrice*=b; totalPrice+=everyPrice; recording[re++]=everyPrice; System.out.println(wholeJudge+" "+order+" "+everyPrice); count++; } wholeJudge=input.next(); } if(!wholeJudge.equals("0")) System.out.println(totalPrice); else System.out.println("0"); } }
代码分析
1.主类过于冗余,判断在输出的信息,应该提取在多个方法中。
2.定义的gettotalprice();注释掉了,使用了一个单独变量作为价格总和。面向过程的代码,复用率低。
3.日期的判断采用的提取字符串。可用Java自带的日期类减少代码量和复杂度。
4.程序时间复杂度高。过测试点过的很极限。
5.桌类的定义没有很好的与前几个类组合一起,方法的定义很长。


7-6日期问题面向对象设计(聚合二)

SourceMonitor的生成报表如下:
可见主类的复杂度很高,Date的复杂度也很高(test类为测试类)。
public ResultData getNextDay(String date) throws ParseException { //格式化 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); if (StringUtils.isEmpty(date)){ //抛出自定义异常 throw new CherishException(20000,"时间不能空"); } //转换成时间类 Date date1 = sdf.parse(date); //获得日历类 Calendar calendar=Calendar.getInstance(); calendar.setTime(date1); // 把日期往后增加一天.整数往后推,负数往前移动 calendar.add(Calendar.DATE,1); //返回增加一天后的时间。 String time = sdf.format(calendar.getTime()); return ResultData.ok().data("time",time); }
常用的Calendar的封装好的方法
import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class DateUtils { public static final String DAFAULT_DATE_FORMAT = "yyyy-M-d"; public static final String DATE_FORMAT = "yyyy-MM-dd"; public static final String DAFAULT_DATETIME_FORMAT = "yyyy-M-d HH:mm:ss"; public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String DAFAULT_TIME_FORMAT = "HH:mm:ss"; /** * 默认构造方法 */ private DateUtils() { } /** * 当前时间 * * @return date */ public static Date currentDate() { return Calendar.getInstance().getTime(); } /** * 得到年 * * @param c * @return */ public static int getYear(Calendar c) { if (c != null) { return c.get(Calendar.YEAR); } else { return Calendar.getInstance().get(Calendar.YEAR); } } /** * 得到月份 * 注意,这里的月份依然是从0开始的 * * @param c * @return */ public static int getMonth(Calendar c) { if (c != null) { return c.get(Calendar.MONTH) + 1; } else { return Calendar.getInstance().get(Calendar.MONTH) + 1; } } /** * 得到日期 * * @param c * @return */ public static int getDate(Calendar c) { if (c != null) { return c.get(Calendar.DATE); } else { return Calendar.getInstance().get(Calendar.DATE); } } /** * 得到星期 * * @param c * @return */ public static int getDay(Calendar c) { if (c != null) { return c.get(Calendar.DAY_OF_WEEK); } else { return Calendar.getInstance().get(Calendar.DAY_OF_WEEK); } } /** * 得到小时 * * @param c * @return */ public static int getHour(Calendar c) { if (c != null) { return c.get(Calendar.HOUR_OF_DAY); } else { return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); } } /** * 得到分钟 * * @param c * @return */ public static int getMinute(Calendar c) { if (c != null) { return c.get(Calendar.MINUTE); } else { return Calendar.getInstance().get(Calendar.MINUTE); } } /** * 得到秒 * * @param c * @return */ public static int getSecond(Calendar c) { if (c != null) { return c.get(Calendar.SECOND); } else { return Calendar.getInstance().get(Calendar.SECOND); } } /** * 得到指定或者当前时间前n天的Calendar * * @param c * @param n * @return */ public static Calendar beforeNDays(Calendar c, int n) { //偏移量,给定n天的毫秒数 long offset = n * 24 * 60 * 60 * 1000; Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } calendar.setTimeInMillis(calendar.getTimeInMillis() - offset); return calendar; } /** * 得到指定或者当前时间后n天的Calendar * * @param c * @param n * @return */ public static Calendar afterNDays(Calendar c, int n) { //偏移量,给定n天的毫秒数 long offset = n * 24 * 60 * 60 * 1000; Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } calendar.setTimeInMillis(calendar.getTimeInMillis() + offset); return calendar; } /** * 指定日期加月份 * * @param date 指定日期 * @param addMonths 要加的月份数 * @return Date 计算后的日期 */ public static Date addMonths(Date date, int addMonths) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.MONTH, addMonths); return calendar.getTime(); } /** * 当前日期加月份 * * @param addMonths 要加的月份数 * @return Date 计算后的日期 */ public static Date addMonths(int addMonths) { return addMonths(new Date(), addMonths); } /** * 指定日期加天 * * @param date 指定日期 * @param addDays 要加的天数 * @return Date 计算后的日期 */ public static Date addDays(Date date, int addDays) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DATE, addDays); return calendar.getTime(); } /** * 当前日期加天 * * @param addDays 要加的天数 * @return Date 计算后的日期 */ public static Date addDays(int addDays) { return addDays(new Date(), addDays); } /** * 指定日期加小时 * * @param date 指定日期 * @param addHours 要加的小时数 * @return Date 计算后的日期 */ public static Date addHours(Date date, int addHours) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.HOUR, addHours); return calendar.getTime(); } /** * 当前日期加小时 * * @param addHours 要加的小时数 * @return Date 计算后的日期 */ public static Date addHours(int addHours) { return addHours(new Date(), addHours); } /** * 指定日期加分 * * @param date 指定日期 * @param addMinutes 要加的分数 * @return Date 计算后的日期 */ public static Date addMinutes(Date date, int addMinutes) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.MINUTE, addMinutes); return calendar.getTime(); } /** * 当前日期加分 * * @param addMinutes 要加的分数 * @return Date 计算后的日期 */ public static Date addMinutes(int addMinutes) { return addMinutes(new Date(), addMinutes); } /** * 指定日期加秒 * * @param date 指定日期 * @param addSeconds 要加的秒数 * @return Date 计算后的日期 */ public static Date addSeconds(Date date, int addSeconds) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.SECOND, addSeconds); return calendar.getTime(); } /** * 当前日期加秒 * * @param addSeconds 要加的秒数 * @return Date 计算后的日期 */ public static Date addSeconds(int addSeconds) { return addSeconds(new Date(), addSeconds); } /** * 昨天 * * @param c * @return */ public static Calendar yesterday(Calendar c) { long offset = 1 * 24 * 60 * 60 * 1000; Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } calendar.setTimeInMillis(calendar.getTimeInMillis() - offset); return calendar; } /** * 明天 * * @param c * @return */ public static Calendar tomorrow(Calendar c) { long offset = 1 * 24 * 60 * 60 * 1000; Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } calendar.setTimeInMillis(calendar.getTimeInMillis() + offset); return calendar; } /** * 得到指定或者当前时间前offset毫秒的Calendar * * @param c * @param offset * @return */ public static Calendar before(Calendar c, long offset) { Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } calendar.setTimeInMillis(calendar.getTimeInMillis() - offset); return calendar; } /** * 得到指定或者当前时间前offset毫秒的Calendar * * @param c * @param offset * @return */ public static Calendar after(Calendar c, long offset) { Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } calendar.setTimeInMillis(calendar.getTimeInMillis() - offset); return calendar; } /** * 日期格式化 * * @param c * @param pattern * @return */ public static String format(Calendar c, String pattern) { Calendar calendar = null; if (c != null) { calendar = c; } else { calendar = Calendar.getInstance(); } if (pattern == null || pattern.equals("")) { pattern = DATETIME_FORMAT; } SimpleDateFormat sdf = new SimpleDateFormat(pattern); return sdf.format(calendar.getTime()); } /** * 日期格式化 * * @param date 日期 * @param pattern 格式 * @return String 格式化字符串 */ public static String format(Date date, String pattern) { Date tempDate = null; if (date != null) { tempDate = date; } else { tempDate = Calendar.getInstance().getTime(); } if (pattern == null || pattern.equals("")) { pattern = DATETIME_FORMAT; } SimpleDateFormat sdf = new SimpleDateFormat(pattern); return sdf.format(tempDate); } /** * Date类型转换到Calendar类型 * * @param d * @return */ public static Calendar date2Calendar(Date d) { Calendar c = Calendar.getInstance(); c.setTime(d); return c; } /** * Calendar类型转换到Date类型 * * @param c * @return */ public static Date calendar2Date(Calendar c) { return c.getTime(); } /** * Date类型转换到Timestamp类型 * * @param d * @return */ public static Timestamp date2Timestamp(Date d) { return new Timestamp(d.getTime()); } /** * Calendar类型转换到Timestamp类型 * * @param c * @return */ public static Timestamp calendar2Timestamp(Calendar c) { return new Timestamp(c.getTimeInMillis()); } /** * Timestamp类型转换到Calendar类型 * * @param ts * @return */ public static Calendar timestamp2Calendar(Timestamp ts) { Calendar c = Calendar.getInstance(); c.setTime(ts); return c; } /** * 得到当前时间的字符串表示 * 格式2010-02-02 12:12:12 * * @return */ public static String getTimeString() { return format(Calendar.getInstance(), DATETIME_FORMAT); } /** * 标准日期格式字符串解析成Calendar对象 * * @param s * @return */ public static Calendar pars2Calender(String s) { Timestamp ts = Timestamp.valueOf(s); return timestamp2Calendar(ts); } }
我尝试了在求前n天的方法中用long型和biginteger但都还是运行超时(我判断是循环次数过多导致超时),最后我通过了一个先判断n是否大于400年的天数(),然后在减掉a个400年的天数在进入循环,最后返回的年数再加a*400。
题目集六:菜单计价-4
对于我来说这题确实有些超纲了,只能过部分测试点,代码如下:
import java.util.*; public class Main { private static Scanner scanner = new Scanner(System.in); private static Menu menu = new Menu(); private static ArrayList<Order> orders = new ArrayList<>(); public static void main(String[] args) { readMenu(); table(); readOrders(); calculateOrderPrices(); printOrders(); } private static void table() { while (true) { String line = scanner.nextLine(); if (line.equals("end") || line.charAt(0) == 't') { break; } String[] parts = line.split(" "); if(parts[1].equals('a')){ System.out.println("wrong format"); }else if(parts.length== 4){ String[] s1 = parts[2].split("/"); String[] s2 = parts[3].split("/"); }else{ System.out.println("wrong format"); } } } // 读取菜单信息 private static void readMenu() { while (true) { String line = scanner.nextLine(); if (line.equals("end") || line.charAt(0) == 't') { break; } String[] parts = line.split(" "); if(parts[0].matches("\\d+")) menu.addDish(parts[0], Integer.parseInt(parts[1])); } } // 读取订单信息 private static void readOrders() { while (true) { String line = scanner.nextLine(); if (line.equals("end")) { break; } String[] parts = line.split(" "); int orderNum = Integer.parseInt(parts[0]); if (parts[1].equals("delete")) { // 删除订单记录 Order order = orders.get(orders.size() - 1); if (!order.delRecordByOrderNum(orderNum)) { System.out.println("delete error"); } } else { // 添加订单记录 String dishName = parts[1]; int portion = Integer.parseInt(parts[2]); int num = Integer.parseInt(parts[3]); Dish dish = menu.searchDish(dishName); if (dish == null) { System.out.println("** does not exist"); return; } Order order = orders.get(orders.size() - 1); order.addRecord(orderNum, dish, portion, num); } } } private static void calculateOrderPrices() { for (Order order : orders) { int totalPrice = order.getTotalPrice(); int hour = Integer.parseInt(scanner.nextLine()); if (isInOpeningHours(hour)) { if (isWeekday(hour)) { if (isDinner(hour)) { totalPrice = Math.round(totalPrice * 0.8f); } else if (isLunch(hour)) { totalPrice = Math.round(totalPrice * 0.6f); } } else { System.out.println("table " + order.getTableNum() + " out of opening hours"); return; } int discountPrice = Math.round(totalPrice * 0.1f); int finalPrice = totalPrice - discountPrice; System.out.println("table " + order.getTableNum() + ": " + totalPrice + " " + finalPrice); } } } private static boolean isWeekend(int hour) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); return dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY; } // 判断是否是工作日 private static boolean isWeekday(int hour) { return !isWeekend(hour); } // 判断是否是午餐时间 private static boolean isLunch(int hour) { return hour >= 10 * 60 + 30 && hour <= 14 * 60 + 30; } // 判断是否是晚餐时间 private static boolean isDinner(int hour) { return hour >= 17 * 60 && hour <= 20 * 60 + 30; } // 判断是否在营业时间 private static boolean isInOpeningHours(int hour) { return (isWeekend(hour) && hour >= 9 * 60 + 30 && hour <= 21 * 60 + 30) || (isWeekday(hour) && (isLunch(hour) || isDinner(hour))); } private static void printOrders() { for (Order order : orders) { ArrayList<Record> records = order.getRecords(); System.out.println("table " + order.getTableNum() + ":"); for (Record record : records) { int price = record.getPrice() * record.getNum(); System.out.println(record.getOrderNum() + " " + record.getDish().getName() + " " + price); } int totalPrice = order.getTotalPrice(); int discountPrice = Math.round(totalPrice * 0.1f); int finalPrice = totalPrice - discountPrice; System.out.println("total " + totalPrice + " " + finalPrice); } } } //定义Dish类 class Dish { private String name; // 菜品名称 private int unitPrice; // 单价 public Dish(String name, int unitPrice) { this.name = name; this.unitPrice = unitPrice; } public String getName() { return name; } public int getUnitPrice() { return unitPrice; } public int getPrice(int portion) { if (portion == 1) { return unitPrice; // 小份 } else if (portion == 2) { return Math.round(unitPrice * 1.5f); // 中份 } else if (portion == 3) { return unitPrice * 2; // 大份 } else { return 0; // 错误情况 } } } //定义Menu类 class Menu { private ArrayList<Dish> dishes; public Menu() { dishes = new ArrayList<>(); } public Dish searchDish(String dishName) { for (Dish dish : dishes) { if (dish.getName().equals(dishName)) { return dish; } } return null; } public boolean addDish(String dishName, int unitPrice) { if (searchDish(dishName) != null) { return false; // 菜已经存在 } dishes.add(new Dish(dishName, unitPrice)); return true; } }//定义Order类class Order { private int tableNum; // 桌号 private ArrayList<Record> records; public Order(int tableNum) { this.tableNum = tableNum; records = new ArrayList<>(); } public int getTableNum() { return tableNum; } public ArrayList<Record> getRecords() { return records; } public int getTotalPrice() { int totalPrice = 0; for (Record record : records) { totalPrice += record.getPrice(); } return totalPrice; } public Record addRecord(int orderNum, Dish dish, int portion, int num) { Record record = new Record(orderNum, dish, portion); records.add(record); return record; } public boolean delRecordByOrderNum(int orderNum) { for (int i = 0; i < records.size(); i++) { if (records.get(i).getOrderNum() == orderNum) { records.remove(i); return true; } } return false; } public Record findRecordByNum(int orderNum) { for (Record r : records) { if (r.getOrderNum() == orderNum) { return r; } } return null; } }//定义Reco类 class Record { private int orderNum; // 序号 private Dish dish; // 菜品 private int portion; // 份额(1/2/3代表小/中/大份) private int num; public Record(int orderNum, Dish dish, int portion) { this.orderNum = orderNum; this.dish = dish; this.portion = portion; } public int getOrderNum() { return orderNum; } public Dish getDish() { return dish; } public int getPortion() { return portion; } public int getPrice() { return dish.getPrice(portion); } public int getNum() { return num; } }
三、踩坑心得
- 有一个正则表达式运行起来会一直超时,经查阅各种资料也不知道为啥,代码如下:
newinput = newinput.replaceAll("(/\\*)(\n*.*?)*(\\*/)", " "); //newinput = newinput.replaceAll("(/\\*)(\n*.*)(\\*/)", " ");后续改成下面那行就不会超时了,本人推测是在下划线那部分持续判断出不来导致的
- 有时候find()和maches()会用混淆
- 慎用正则表达式的" () "和" | "
- key值和value值的使用很容易搞反一定要细心!
四、改进建议
脑子再灵活一点,多思考多编程!
五、总结
1.做题总结:
(1)做题尽量一次性做完,尤其是写代码比较多的题目,不然很容易忘记一些自己写过的方法,对之前设计的结构也会印象较浅,导致前后思路不一样;
(2)题目的信息要看完全,题目所给信息几乎没有用不上的,如果有,可能就是设计不到位,走了弯路,要反思自己;
(3)做有类图的题目时,可以先尝试不看类图,自己思考一下自己认为的类图应该是怎么样的,然后与题目所给类图对比,看看自己的想法和题目类图的差异并思考题目的类图为何那么设计,自己又在哪方面缺少了这种思想。