场景
学校需要查询某个学生最近一场考试中的语文和数学成绩,学生和考试的关系如图所示:
学生与考试关系图
学生类中包含考试类,一个考试有多个课程成绩对应
Java的实现
定义数据Model
public class Course {
private String name;
private Float score;
// 省略constructor、getter、setter、hasCode、equals、toString等方法
}
public class Examination {
private String type;
private List<Course> courses;
// 省略constructor、getter、setter、hasCode、equals、toString等方法
}
public class Student {
private String name;
private Examination recentExamination;
// 省略constructor、getter、setter、hasCode、equals、toString等方法
}
模拟从数据库或后台服务端获取学生信息的方法
public class JavaSyntaxExample {
private Student getStudentByName(String name) {
List<Course> courses = Arrays.asList(new Course("Math", 99f),
new Course("English", 30f),
new Course("Chinese", null));
double random = Math.random();
System.out.println("random->" + random);
if (random > 0.7) {
return new Student(name, new Examination("midterm", courses));
} else if(random > 0.4) {
return new Student(name, new Examination("midterm", null));
} else {
return null;
}
}
初级程序员展示考试成绩的实现
@Test
public void testExampleByJunior() {
// 从服务端获取数据
Student feifei = getStudentByName("feifei");
// 打印当前学生的语文和数学课程的分数
List<Course> courses = feifei.getRecentExamination().getCourses();
for (int i = 0; i < courses.size(); i++) {
Course course = courses.get(i);
if (course.getName().equals("Chinese")
|| course.getName().equals("Math")) {
System.out.println("学生:" + feifei.getName() + ";" +
course.getName() + "分数:" + course.getScore());
}
}
}
以上的代码,很容易写出,但也容易出现异常和崩溃,因为它没有考虑到判空的问题,运行上面的代码,出现以下结果
// 结果1
// 学生:feifei;Math分数:99.0
// 学生:feifei;Chinese分数:null
// 结果2
// java.lang.NullPointerException
有经验的Java程序员展示考试成绩的实现
@Test
public void testExampleBySenior() {
// 从服务端获取数据
Student feifei = getStudentByName("feifei");
// 打印当前学生的语文和数学课程的分数
if (feifei == null
|| feifei.getRecentExamination() == null
|| feifei.getRecentExamination().getCourses() == null
|| feifei.getRecentExamination().getCourses().isEmpty()) {
// 增加了繁琐的判空处理
System.out.println("学生: feifei;没有记录");
} else {
for (Course course : feifei.getRecentExamination().getCourses()) {
if (course.getName().equals("Chinese")
|| course.getName().equals("Math")) {
// 增加了判空处理
String scoreDesc = "没有记录";
if (course.getScore() != null) {
scoreDesc = course.getScore().toString();
}
System.out.println("学生:" + feifei.name + ";"
+ course.name + "分数:" + scoreDesc);
}
}
}
}
以上代码主要在之前的代码基础上新增了两处判空处理,运行结果如下
// 结果1
// 学生:feifei;Math分数:99.0
// 学生:feifei;Chinese分数:没有记录
// 结果2
// 学生: feifei;没有记录
逻辑上是没有问题的,但整个Java的实现还是令人感觉臃肿、低效:
- 空指针错误不能在编译期检查出来。也就是说我不判空,编译也能通过,不能及时检查出错误。要知道,经验丰富的程序员在时间仓促的情况下,也很容易忘记判空处理。
- 判空处理逻辑繁琐臃肿。第一处判空,为了判断课程成绩是否为空,写了四行判空语句,如果类结构层级更深些,则判空语句会对应的增长,实在是又臭又长。
- 判空处理书写重复啰嗦。第一处判空处理中,
feifei
写了四遍,feifei.getRecentExamination()
写了三遍,令人厌恶。要知道开发人员的时间是很宝贵的,不要浪费时间在重复的事情上。 - 循环遍历展示成绩的逻辑繁琐。这里的
for
循环里包含了两处if
判断就显得臃肿、难看,如果有更多if
判断语句呢?嵌套层次越多,维护成本越高。 - 数据层的实现臃肿。Java写数据类型,一般除了写私有成员变量外,还需要些constructor、getter、setter、hasCode、equals、toString等方法,虽然这些方法的实现在一般的IDE里面都能够自动生成,但还是需要开发人员敲击几个命令或点击几次鼠标,都是重复的工作,还是浪费时间。
- 字符串拼接麻烦。
"学生:" + feifei.name + ";" + course.name + "分数:" + scoreDesc
,在这行语句中,需要写三对引号,五个加号,令人繁琐,开发人员应该把时间用到创造性的事情上,而不是繁琐、重复的事情上。
Kotlin的实现
数据类的实现-简洁
data class Course(val name: String, val score: Float?)
data class Examination(val type: String, val courses: List<Course>?)
data class Student(val name: String, val recentExamination: Examination?)
模拟获取学生对象的实现
class KotlinSyntaxExample {
private fun getStudentByName(name: String): Student? {
val courses = listOf(Course("Chinese", null),
Course("Math", 99f),
Course("English", 30f))
val random = Math.random()
print("random->$random")
return when {
random > 0.7 -> Student(name, Examination("midterm", courses))
random > 0.4 -> Student(name, Examination("midterm", null))
else -> null
}
}
}
展示考试成绩的实现
class KotlinSyntaxExample {
@Test
fun testExample1() {
val feifei = getStudentByName("feifei")
val courses = feifei?.recentExamination?.courses
if (courses == null || courses.isEmpty()) {
println("学生: feifei;没有记录")
} else {
courses.filter { course ->
return@filter course.name == "Chinese" || course.name == "Math"
}
.forEach { course ->
println("学生:${feifei.name};${course.name}:${course.score ?: "没有记录"}")
}
}
// 不加? 编译期间会报错
}
}
从上面的代码可以看出,kotlin的的实现:更安全、简洁。
- 不需要所有的对象都需要显式判空,更加简洁。如
val courses = feifei?.recentExamination?.courses
- 判断课程成绩列表是否为空的实现只需要对课程成绩列表做判空处理即可。如
courses == null || courses.isEmpty()
- 集合使用流式操作,简洁明了。减少了嵌套,降低了维护成本。
- 数据层实现简洁。
- 字符串使用了字符串模板,简洁明了。
总结
本文展示了一个小的示例来比较Java和kotlin常用的操作语法,展示了kotlin语法的简洁、安全、高效,建议使用Java的同学,不妨试试kotlin。
网友评论