話不多說(shuō)企蹭,先看題:
隨機(jī)生成 Salary {name, baseSalary, bonus }
的記錄雳攘,如“wxxx,10,1”谎倔,每行一條記錄沥邻,總共1000萬(wàn)記錄服猪,寫入文本文件(UFT-8編碼)觉阅, 然后讀取文件甚颂,name的前兩個(gè)字符相同的用爪,其年薪累加顽照,比如wx无畔,100萬(wàn)宅粥,3個(gè)人参袱,最后做排序和分組,輸出年薪總額最高的10組:
wx | 200萬(wàn) | 10人 |
lt | 180萬(wàn) | 8人 |
... | ... | ... |
name 4位a-z隨機(jī),baseSalary [0,100]
隨機(jī) bonus[0-5]
隨機(jī) 抹蚀,年薪總額 = baseSalary*13 + bonus剿牺。
思路:
第一步:先編寫一個(gè)Salary對(duì)象
里面包含有name
,baseSalary
, bounus
屬性环壤,然后編寫一個(gè)構(gòu)造器晒来,重寫toString()
方法方便序列化數(shù)據(jù),同時(shí)編寫構(gòu)建Salary對(duì)象的方法build()
郑现;
/**
* name 4位a-z隨機(jī)
* baseSalary 0-100隨機(jī)
* bonus 0-5隨機(jī)
* 年薪總額 = baseSalary * 13 + bonus
*/
class Salary {
// name 4位a-z隨機(jī),baseSalary 0-100隨機(jī),bonus 0-5隨機(jī) 年薪總額 = 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隨機(jī)數(shù)
this.baseSalary = (int)(100 * Math.random());
// 0-5隨機(jī)數(shù)
this.bonus = (int)(5 * Math.random());
return this;
}
@Override
public String toString() {
return name + " " + baseSalary + " " + bonus;
}
/**
* 生產(chǎn)Name隨機(jī)函數(shù) 4位a-z隨機(jī)
* @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
寫入文件
/**
* 寫入文件
* @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進(jìn)行寫入
/**
* NIO進(jìn)行寫入
* @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();
}
比較下來(lái)接箫,單純從這個(gè)代碼的性能上講差不太多攒读!
第三步:讀取并解析文件在進(jìn)行排序
? a) 通過(guò)JAVA的IO進(jìn)行讀取:
/**
* 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)); // 建立一個(gè)輸入流對(duì)象reader
BufferedReader br = new BufferedReader(reader); // 建立一個(gè)對(duì)象辛友,它把文件內(nèi)容轉(zhuǎn)成計(jì)算機(jī)能讀懂的語(yǔ)言
String line = ""; // 每一行的內(nèi)容
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]))); // 添加一個(gè)Salary實(shí)體
i++;
}
reader.close();
br.close();
return list;
}
? b) 通過(guò)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]))); // 添加一個(gè)Salary實(shí)體
});
return list;
}
二者比較下來(lái):使用jdk1.8讀取更簡(jiǎn)單,效率性能更高瞎领!
第四步:使用JDK8的Stream進(jìn)行排序和截取
/**
* 排序并獲取前十?dāng)?shù)據(jù)
* @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());
});
}
同時(shí)將數(shù)據(jù)封裝在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數(shù)據(jù)基本上1分鐘不到就可以完成寫入和讀取泌辫,歡迎大家進(jìn)行改寫和優(yōu)化随夸。