记录MTV最常点的歌(出自head fist java 16 529页)
欢迎你来到大富豪KTV担任点歌系统管理员一职。虽然点歌系统没有内置JAVA,但是只要有人点歌,数据就会自动记录到一个文本文件中。你的工作是要管理点播记录、产生报表和管理歌本。你并不需要写出整个程序—很多同事都是找不到程序设计工作才来当服务生的,所以大家可以分工合作,你只需要负责用JAVA程序来把数据排序。因为老板很抠,所以公司没买数据库应用程序,你只能靠内存上的数据集合,还有记录用的文本文件。用ArrayList来排序。
挑战一
以歌名来排序
文件上列出歌曲,每行代表一曲歌,歌名与歌星用斜线分开,所以应该很容易解析并放在ArrayList上。
消费者通常是看歌名点歌,所以目前只要记住歌名就行。但你会注意到歌曲没有依据字母排序,要怎么办??
你知道使用ArrayList的时候,元素会维持被加入ArrayList的顺序,所以它们不会依照字母排序,或许ArrayList这个类有sort()方法可以用吗?
Communication/The Cardigans
Black Dog/Led Zeppelin
Dreams/Van Halen
Comfortably Numb/Pink Floyd
Beth/Kiss
倒退噜/黄克林
这是点歌系统写出的文件,你的程序必须读取文件才能操作数据。
import java.util.*;
import java.io.*;
public class Jukebox1{
ArrayList<String> songList=new ArrayList<String>(); //歌曲名称全存在String的ArrayList上
public static void main(String[] args)
{
new Jukebox1().go();
}
public void go()
{
getSongs(); //这个方法会载入文件并列出内容
System.out.println(songList);
}
void getSongs() //读取文件的程序
{
try{
File file=new File("SongList.txt");
BufferedReader reader=new BufferedReader(new FileReader(file));
String line =null;
while((line=reader.readLine())!=null)
{addSong(line);}
}catch(Exception ex){ex.printStackTrace();}
}
void addSong(String lineToParse)
{
String[] tokens=lineToParse.split("/"); //Split()方法会用反斜线来拆开歌曲内容
songList.add(tokens[0]); //因为只需要歌名,所以只取第一项加入SongList
}
}
ArrayList有一大堆方法,但是没有可以排序的。。。。
ArrayList不是唯一集合
虽然ArrayList会是最常用的。但偶尔还是会有特殊情况。下面列出几个较为重要的:
TreeSet以有序状态保持并可防止重复
HashMap可用成对name/value来保存、退出
LinkedList针对经常插入或删除中间元素所设计的高效率集合(实际上还是ArrayList 更实用)
HashSet防止重复的集合,可快速地找寻相符元素。
LinkedHashMap类似HashMap,但可以记住元素插入顺序,也可以设定成依照元素上次存取的先后来排序。
可以使用TreeSet或者Collections.sort()方法
如果你把字符串放进TreeSet而不是ArrayList,这些String会自动地按照字母顺序排在正确的位置。每当你想列出清单时,元素总是会以字母顺序出现。当你需要Set集合或总是会依照字母排列清单时,它会很好用。
另一方面,如果你没有需要让清单保持有序的状态。TreeSet的成本会比你想付出的还多---每当插入新项目时,它都必须要花很长时间找出适当的位置。而ArrayList只要把项目放在最后边就好。
对点歌系统加上Collections.sort()
public void go() {
getSongs();
System.out.println(songList);
Collections.sort(songList); //调用Connection静态的sort()然后再列出清单。第二次的输出会依照字母排序
System.out.println(songList);
}
调用前 》》》调用后
但是现在要用Song对象而不只是String
老板说list里面要摆的是Song这个类的实例,这样点歌系统才会有更细节的资料可以输出。所以文件内也会从两种数据增加到4种。
Song这个类很单纯,但有一项很有意思的功能:被覆盖过的toString()是定义在Object这个类中,所以Java中的每个类都有继承到,且因为对象被System.out.println(anObject)列出来时会被调用toString(),所以当你要把list列出来时,每个对象的toString()都会被调用一次。
class Song{
//对应四种属性的四个实例变量
String title;
String artist;
String rating;
String bpm;
Song(String t, String a,String r,String b){
//变量都会在创建时从构造函数中设定
title=t; artist=a; rating=r; bpm=b;
}
//四种属性的getter
public String getTitle()
{ return title; }
public String getArtist()
{ return artist; }
public String getRating()
{ return rating; }
public String getBpm()
{ return bpm; }
//将toString()覆盖过,让它返回歌名
public String toString()
{ return title; }
}