1. 从笔试到实战字符串处理的工程化思维第一次看到神州信息的字符串统计题目时我下意识就写了个遍历字符数组的解法。直到在实际项目中处理用户输入时才发现这种看似简单的题目藏着不少坑。比如用户输入了emoji表情怎么办全角数字和半角数字要不要区分统计这些在笔试中不会考虑的问题恰恰是工程实践中的高频问题。先看原始题目要求统计字母、数字、空格和其他字符的数量。笔试给出的Java解法确实能跑通但存在几个潜在问题字符范围判断不够严谨比如漏掉了A和Z的等号情况没有考虑Unicode字符集代码复用性差优化后的工程版本可以这样写public class CharacterCounter { private static final Pattern LETTER Pattern.compile([a-zA-Z]); private static final Pattern DIGIT Pattern.compile(\\d); public static CountResult count(String input) { if (input null) return new CountResult(0, 0, 0, 0); int letters 0; int digits 0; int spaces 0; int others 0; for (char c : input.toCharArray()) { if (LETTER.matcher(String.valueOf(c)).matches()) { letters; } else if (DIGIT.matcher(String.valueOf(c)).matches()) { digits; } else if (Character.isWhitespace(c)) { spaces; } else { others; } } return new CountResult(letters, digits, spaces, others); } public static class CountResult { // 省略getter方法 } }这个版本有三个改进点使用正则表达式提高可读性增加空指针检查封装统计结果为对象在实际的日志分析系统中我们还需要考虑更多边界情况。比如处理GBK编码的日志文件时中文字符会被识别为其他字符这时就需要根据业务需求调整统计规则。2. 日期计算题的实战变形记那道计算一年中第几天的题目我在真实项目中遇到过至少三种变形计算两个日期间的工作日天数排除周末和节假日生成指定时间范围内的日期序列处理不同时区的日期转换原始解法的问题在于闰年判断条件有误y/1000应该是y/100switch语句存在重复计算没有日期合法性校验这是我在金融项目中使用的日期工具类片段public class DateUtils { private static final int[] DAYS_IN_MONTH {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; public static int dayOfYear(LocalDate date) { if (date null) throw new IllegalArgumentException(); int day date.getDayOfMonth(); int month date.getMonthValue(); int year date.getYear(); if (month 2 isLeapYear(year)) { day; } for (int i 0; i month - 1; i) { day DAYS_IN_MONTH[i]; } return day; } private static boolean isLeapYear(int year) { return (year % 400 0) || (year % 100 ! 0 year % 4 0); } }这个实现有几个工程化改进使用Java 8的LocalDate避免底层计算错误提取月份天数数组消除重复计算增加参数校验正确的闰年判断逻辑在电商系统中我们还需要处理促销活动的特殊日期规则。比如双十一期间按活动周计算这时就需要在基础日期计算上增加业务规则层。3. 笔试代码的五个致命陷阱回看笔试代码我总结了新手常踩的五个坑3.1 边界条件的集体遗忘字符串题目没有考虑空字符串情况日期题目缺少月份有效范围检查。在实际项目中这类边界问题会导致最严重的生产事故。建议养成编写边界测试用例的习惯Test public void testEmptyString() { CountResult result CharacterCounter.count(); assertEquals(0, result.getLetters()); } Test public void testInvalidDate() { assertThrows(IllegalArgumentException.class, () - DateUtils.dayOfYear(LocalDate.of(2023, 13, 1))); }3.2 运算符的迷惑行为像把写成这类错误在IDE里会被立即发现但更危险的是逻辑运算符的误用。比如闰年判断中的和||组合建议用括号明确优先级// 好的写法 if ((year % 4 0 year % 100 ! 0) || year % 400 0) // 危险的写法 if (year % 4 0 year % 100 ! 0 || year % 400 0)3.3 魔法数字的诅咒原始代码中大量出现的31、30等数字会增加维护成本。应该定义为常量private static final int DAYS_IN_JANUARY 31; private static final int DAYS_IN_APRIL 30;3.4 流程控制的漏洞switch语句忘记写break是经典错误但在现代Java中更推荐使用枚举替代public enum Month { JANUARY(31), FEBRUARY(28), // ... private final int days; Month(int days) { this.days days; } public int getDays(boolean leapYear) { if (this FEBRUARY leapYear) { return 29; } return days; } }3.5 异常处理的缺失工程代码必须考虑异常情况。比如日期计算应该校验if (month 1 || month 12) { throw new IllegalArgumentException(Invalid month: month); }4. 字符串与日期处理的进阶实战在真实项目中我们往往需要处理更复杂的需求。比如最近做的日志分析系统就遇到几个典型场景4.1 多语言环境下的字符串统计当系统需要支持多语言时简单的字符类型判断就不够用了。比如中文的一要不要计入字母这时需要明确业务规则// 中文字符处理方案 if (Character.UnicodeBlock.of(c) Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) { // 根据业务需求决定是否计入字母 if (countChineseAsLetter) { letters; } else { others; } }4.2 时区敏感的日期计算跨境业务必须考虑时区问题。计算用户本地时间的年度第几天public static int dayOfYearInTimezone(ZonedDateTime zdt) { return zdt.withZoneSameInstant(ZoneId.of(Asia/Shanghai)) .getDayOfYear(); }4.3 高性能批量处理当需要处理GB级别的日志文件时原始的单字符遍历方式性能堪忧。这时可以采用正则表达式批量匹配// 高性能统计方案 Matcher letterMatcher LETTER.matcher(input); while (letterMatcher.find()) letters; Matcher digitMatcher DIGIT.matcher(input); while (digitMatcher.find()) digits;4.4 日期规则的动态配置营销活动经常需要动态调整日期规则我们可以设计规则引擎public interface DateRule { boolean isSpecialDay(LocalDate date); } public class PromotionDateService { private ListDateRule rules; public int getBusinessDays(LocalDate start, LocalDate end) { // 应用所有规则计算工作日 } }在真实工程中字符串和日期处理从来不是简单的算法题。每次看到笔试题目我都会想起那些因为考虑不周全而加班调试的夜晚。现在我的编码习惯已经变成先写测试用例再实现功能最后补充文档说明。这种工程化思维或许才是笔试题目想要考察的核心能力。