話很少說,先看題:java
隨機生成 Salary {name, baseSalary, bonus }的記錄,如「wxxx,10,1」,每行一條記錄,總共1000萬記錄,寫入文本文件(UFT-8編碼), 而後讀取文件,name的前兩個字符相同的,其年薪累加,好比wx,100萬,3我的,最後作排序和分組,輸出年薪總額最高的10組:app
wx, 200萬,10人dom
lt, 180萬,8人ide
....函數
name 4位a-z隨機,baseSalary [0,100]隨機 bonus[0-5]隨機 ,年薪總額 = baseSalary*13 + bonus。性能
思路:優化
裏面包含有name,baseSalary, bounus屬性,而後編寫一個構造器,重寫toString()方法方便序列化數據,同時編寫構建Salary對象的方法build();ui
/** * name 4位a-z隨機 * baseSalary 0-100隨機 * bonus 0-5隨機 * 年薪總額 = baseSalary * 13 + bonus */ class Salary { // name 4位a-z隨機,baseSalary 0-100隨機,bonus 0-5隨機 年薪總額 = baseSalary * 13 + bonus private String name; private int baseSalary; private int bonus; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getBaseSalary() { return baseSalary; } public void setBaseSalary(int baseSalary) { this.baseSalary = baseSalary; } public int getBonus() { return bonus; } public void setBonus(int bonus) { this.bonus = bonus; } public Salary() { } public Salary(String name, int baseSalary, int bonus) { this.name = name; this.baseSalary = baseSalary; this.bonus = bonus; } public Salary build() { this.name = getRandomName(4); // 0-100隨機數 this.baseSalary = (int)(100 * Math.random()); // 0-5隨機數 this.bonus = (int)(5 * Math.random()); return this; } @Override public String toString() { return name + " " + baseSalary + " " + bonus; } /** * 生產Name隨機函數 4位a-z隨機 * @param length * @return */ private static String getRandomName(int length ){ String base = "abcdefghijklmnopqrstuvwxyz"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for ( int i = 0; i < length; i++ ){ int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } }
a) 第一種方式,使用Java的IO中BufferedWriter寫入文件this
/** * 寫入文件 * @return * @throws IOException */ public static File writeBuffer() throws IOException { File file = new File(FILE_NAME); FileOutputStream fos = new FileOutputStream(file); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos)); int i = AMOUNT; while(i > 0) { Salary salary = new Salary().build(); writer.write(salary.toString() + "\r\n"); i --; } writer.close(); fos.close(); return file; }
b) 第二種方式,使用JAVA的NIO中的FileChannel進行寫入編碼
/** * NIO進行寫入 * @throws IOException */ private static void writeNIO() throws IOException { FileOutputStream fos = new FileOutputStream(FILE_NAME, true); FileChannel channel = fos.getChannel(); int i = AMOUNT; StringBuffer content = new StringBuffer(); while(i > 0) { Salary salary = new Salary().build(); content.append(salary.toString()).append("\r\n"); i --; } ByteBuffer buf = ByteBuffer.wrap(content.toString().getBytes()); buf.put(content.toString().getBytes()); buf.flip(); channel.write(buf); channel.close(); fos.close(); }
比較下來,單純從這個代碼的性能上講差不太多!
a) 經過JAVA的IO進行讀取:
/** * Java IO讀取文件的方式 * @return * @throws Exception */ public static List<Salary> readFileIO() throws Exception { File file = new File(FILE_NAME); List<Salary> list = new ArrayList<>(); InputStreamReader reader = new InputStreamReader(new FileInputStream(file)); // 創建一個輸入流對象reader BufferedReader br = new BufferedReader(reader); // 創建一個對象,它把文件內容轉成計算機能讀懂的語言 String line = ""; // 每一行的內容 int i = 1; while ((line = br.readLine()) != null) { String[] split = line.trim().split(" ");// .trim()能夠去掉首尾多餘的空格 list.add(new Salary(split[0], Integer.valueOf(split[1]), Integer.valueOf(split[2]))); // 添加一個Salary實體 i++; } reader.close(); br.close(); return list; }
b) 經過JAVA的NIO讀取:
/** * JDK8 NIO讀取文件 * @return * @throws Exception */ public static List<Salary> readFileNIO() throws Exception { List<Salary> list = new ArrayList<>(); Files.lines(Paths.get(FILE_NAME)).forEach(line -> { String[] split = line.trim().split(" ");// .trim()能夠去掉首尾多餘的空格 list.add(new Salary(split[0], Integer.valueOf(split[1]), Integer.valueOf(split[2]))); // 添加一個Salary實體 }); return list; }
兩者比較下來:使用jdk1.8讀取更簡單,效率性能更高!
/** * 排序並獲取前十數據 * @param salaries */ public static void sort(List<Salary> salaries) { Map<String, GroupSalary> result = new HashMap<>(); salaries.forEach(salary -> { String shortName = salary.getName().substring(0, 2); GroupSalary groupSalary = null; List<Salary> salaryList = null; if (result.containsKey(shortName)) { groupSalary = result.get(shortName); salaryList = groupSalary.getSalaries(); } else { groupSalary = new GroupSalary(); salaryList = new ArrayList<>(); groupSalary.setSalaries(salaryList); } salaryList.add(salary); groupSalary.setShortName(shortName); groupSalary.setTotal(groupSalary.getTotal() + salary.getBaseSalary() * 13 + salary.getBonus()); result.put(shortName, groupSalary); }); List<GroupSalary> r = result.entrySet().stream() .sorted((Map.Entry<String, GroupSalary> o1, Map.Entry<String, GroupSalary> o2) -> o2.getValue().getTotal() - o1.getValue().getTotal()) .map(entry -> entry.getValue()).collect(Collectors.toList()).subList(0,10); r.forEach(groupSalary -> { System.out.println(groupSalary.getShortName() + " " + groupSalary.getTotal() + " " + groupSalary.getSalaries().size()); }); }
同時將數據封裝在GroupSalary中
class GroupSalary { private List<Salary> salaries; private String shortName; private int total; public List<Salary> getSalaries() { return salaries; } public void setSalaries(List<Salary> salaries) { this.salaries = salaries; } public String getShortName() { return shortName; } public void setShortName(String shortName) { this.shortName = shortName; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } }
到此若是寫入100W數據基本上1分鐘不到就能夠完成寫入和讀取,歡迎你們進行改寫和優化,具體代碼請去: