遇到一道经典的java面试题

时间:2021-05-25 14:20:49

在文件 nameList.txt 中按下图格式存放着超过50万人的姓名与身份证信息。请使用您熟悉的编程语言(Java或C/C++)编写一段程序, 将出生日期落在1995年1月1日与1999年12月31日之间的个人信息取出,按年龄从大到小排列并输出到另一个txt文件中。 请重点考虑程序的健壮性和排序效率

遇到一道经典的java面试题

小生想到思路:

  1. 先读取文本内容;

  2. 将头信息读取出来,并记录住;

  3. 将真实数据按照行进行读取并封装到 javabean 中:每读取一行,将这行的数据用javabean封装,将这个javabean添加到 list 列表中:

  4. 将得到的 list 列表进行排序,按照出生日期排序,这题正好:出生日期可以作为数字来看待,数字小的就是出生早的;

  5. 将头信息和 list 列表再输出到指定文件中

注意:

题目是要求50万条数据记录进行读取排序,所以一定要想到包装类IO

还有就是要考虑健壮性和排序效率,健壮性,最完美的设计就是无论传递给程序什么javabean,程序都能把读到的数据封装成这个javabean

小生想到的就是动态代理和泛型。

具体实现代码如下(小生这里没有采用包装类了):

 

  1 package com.hy.demo;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileNotFoundException;
  6 import java.io.FileOutputStream;
  7 import java.io.IOException;
  8 import java.lang.reflect.Constructor;
  9 import java.nio.ByteBuffer;
 10 import java.nio.CharBuffer;
 11 import java.nio.channels.FileChannel;
 12 import java.nio.charset.Charset;
 13 import java.util.ArrayList;
 14 import java.util.Collections;
 15 import java.util.List;
 16 
 17 import com.hy.demo.UserComparator.SortType;
 18 
 19 public class DemoTest {
 20     public static void main(String[] args) {
 21         String inpathName = "D:/Workspaces/eclipse-marks-2/hire/src/name_list.txt";
 22 
 23         String content = getFileContent(inpathName);
 24 
 25         // 得到用户数据列表
 26         List<User> userList = getList(content, 3,"19950101","19991231");
 27         // 按照出生日期排序用户列表
 28         String context = orderByUser(userList, SortType.ASC);
 29         // 获取头信息
 30         String header = getHeader(content, 3);
 31         String outpathName = "D:/Workspaces/eclipse-marks-2/hire/src/a.txt";
 32         write(header, context, outpathName);
 33     }
 34     
 35     public static void write(String header,String context,String outPathName) {
 36         FileOutputStream fos =null;
 37         try {
 38             fos = new FileOutputStream(outPathName);
 39             fos.write(header.getBytes());
 40             fos.write(context.getBytes());
 41             
 42             fos.flush();
 43         } catch (IOException e) {
 44             e.printStackTrace();
 45         } finally {
 46             if(fos!=null) {
 47                 try {
 48                     fos.close();
 49                 } catch (IOException e) {
 50                     e.printStackTrace();
 51                 }
 52             }
 53         }
 54         
 55     }
 56     
 57     /**
 58      * 对用户列表排序,并输出成文本格式
 59      * @param list
 60      * @param sortType ASC:按照出生日期升序,DESC:按照出生降序
 61      * @return
 62      */
 63     public static String orderByUser(List<User> list,SortType sortType) {
 64         if(list!=null && list.size()>0) {
 65             Collections.sort(list, new UserComparator(sortType));
 66             StringBuffer sb = new StringBuffer();
 67             
 68             for(int i=0;i<list.size();i++) {
 69                 User user = list.get(i);
 70                 sb.append(user.getName()).append("   \t\t");
 71                 sb.append(user.getGener()).append("\t\t");
 72                 sb.append(user.getIdCard()).append("\t\t");
 73                 sb.append(user.getAddress()).append("\r\n");
 74             }
 75             return sb.toString();
 76         }
 77         return null;
 78     }
 79 
 80     /**
 81      * 读取文本,获取数据源
 82      * 
 83      * @param path
 84      * @return
 85      */
 86     public static String getFileContent(String path) {
 87         File file = new File(path);
 88         // 分配新的直接字节缓冲区
 89         ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
 90         StringBuffer stringBuffer = new StringBuffer(1024);
 91         try {
 92             FileInputStream fileInputStream = new FileInputStream(file);
 93             // 用于读取、写入、映射和操作文件的通道。
 94             FileChannel fileChannel = fileInputStream.getChannel();
 95             // 编码字符集和字符编码方案的组合,用于处理中文,可以更改
 96             Charset charset = Charset.forName("UTF-8");
 97             while (fileChannel.read(byteBuffer) != -1) {
 98                 // 反转此缓冲区
 99                 byteBuffer.flip();
100                 CharBuffer charBuffer = charset.decode(byteBuffer);
101                 stringBuffer.append(charBuffer.toString());
102                 byteBuffer.clear();
103             }
104             fileInputStream.close();
105         } catch (FileNotFoundException e) {
106             e.printStackTrace();
107         } catch (IOException e) {
108             e.printStackTrace();
109         }
110         return stringBuffer.toString();
111     }
112 
113     /**
114      * 获取数据列表
115      * @param <T>
116      * @param content    
117      * @param num    指定头信息含有多少行
118      * @return
119      */
120     public static List getList(String content, int num,String start, String end) {
121         
122         // 将文本行信息按照行截取
123         String[] strs = content.split("\r\n");
124         
125         if(num>strs.length) {
126             throw new RuntimeException("文本头行数参数不能大于文本总行数!");
127         }
128         
129         // 接收数据,按照行接收
130         List<User> list = new ArrayList<User>();
131         Integer date;
132         for (int i = num; i < strs.length; i++) {
133             // 将每一行的数据封装到User对象中
134             String[] userParams = strs[i].split("\t\t");
135             User user = new User();
136             user.setName(userParams[0]);
137             user.setGener(userParams[1]);
138             user.setIdCard(userParams[2]);
139             user.setAddress(userParams[3]);
140             // 将每一行数据添加到列表中
141             
142             // 选择出生日期区间
143             if(start!=null&&!"".equals(start) && end!=null&&!"".equals(end)) {
144                 date = Integer.parseInt(user.getIdCard().substring(6, 14));
145                 if(date>= Integer.parseInt(start)&&date<=Integer.parseInt(end) ) {
146                     list.add(user);
147                 }
148             }
149         }
150         return list;
151     }
152 
153     /**
154      * 获取头信息
155      * @param context    指定要获取的文本内容
156      * @param num    指定获前几行
157      * @return
158      */
159     public static String getHeader(String context, int num) {
160         // 将文本行信息按照行截取
161         String[] strs = context.split("\r\n");
162         // 接收头信息
163         StringBuffer headStringBuffer = new StringBuffer();
164 
165         for (int i = 0; i < num; i++) {
166             headStringBuffer.append(strs[i]).append("\r\n");
167         }
168         // 获取头信息
169         return headStringBuffer.toString();
170     }
171 
172 }

 

javabean封装类:

public class User {
    private String name;
    private String gener;
    private String idCard;
    private String address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGener() {
        return gener;
    }
    public void setGener(String gener) {
        this.gener = gener;
    }
    public String getIdCard() {
        return idCard;
    }
    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", gener=" + gener + ", idCard=" + idCard + ", address=" + address + "]";
    }
    
}

 

javabean比较器:

public class UserComparator implements Comparator<User> {

    public enum SortType {
        ASC, DESC
    }

    public UserComparator(SortType sortType) {
        this.sortType = sortType;
    }

    private SortType sortType;

    @Override
    public int compare(User o1, User o2) {
        int o1Date = Integer.parseInt(o1.getIdCard().substring(6, 14));
        int o2Date = Integer.parseInt(o2.getIdCard().substring(6, 14));
        switch (sortType) {
        case ASC:
            if (o1Date > o2Date) {
                return 1;
            } else if (o1Date < o2Date) {
                return -1;
            }
            break;
        case DESC:
            if (o1Date > o2Date) {
                return -1;
            } else if (o1Date > o2Date) {
                return 1;
            }
            break;

        default:
            break;
        }
        return 0;
    }

}

 

读者们,如果有更好思路和细节处理,欢迎留言讨论,谢谢!