ARTS - 2020.08.31 ~ 2020.09.06

ARTS打卡 - 13

1. Algorithm

20. Valid Parentheses

题目是判断字符串是否为有效括号:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

乍一看觉得比较简单,刚开始的想法是顺序遍历字符串,先判断下一个,不符合条件的话就判断len - index是否符合括号闭合条件,写完之后提交用例没过,因为还有这样的字符串 : (([]){}) 也属于有效字符串,所以用我开始的想法肯定是不可行的 ,后来才想到用栈,遍历字符串,先入栈,然后判断当前字符串与栈顶字符串是否符合闭合条件,符合就弹栈,最后判断栈是否为空,空就表示字符串符合闭合条件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if(s == null || s.length() % 2 != 0){
return false;
}

Stack<Character> stack = new Stack<>();

int start = 0;
while (start < s.length()){
if(stack.empty()){
stack.push(s.charAt(start));
start++;
continue;
}
int i = s.charAt(start) - stack.peek();
if(i < 3 && i > 0){
stack.pop();
}else{
stack.push(s.charAt(start));
}
start++;
}

return stack.empty();

这道是easy的题,但是一开始没有想到使用栈来做,所以还是走了一些弯路。

2. Review

Refactoring utility classes with Kotlin : Shared Preferences

这篇文章使用Kotlin将SharedPreferences封装了一个工具类,封装后使用很简单方便,例如:

1
2
3
4
val prefs = defaultPrefs(this)
prefs[Consts.SharedPrefs.KEY] = "any_type_of_value" //setter
val value: String? = prefs[Consts.SharedPrefs.KEY] //getter
val anotherValue: Int? = prefs[Consts.SharedPrefs.KEY, 10] //getter with default value

作者利用了operator 关键字,operator 的作用是重载操作符,对于索引访问操作符例如: get()、set()可以使用operator 进行重载, 实现方式如下:

1
2
3
4
5
6
7
8
9
10
operator inline fun <reified T : Any> SharedPreferences.get(key: String, defaultValue: T? = null): T? {
return when (T::class) {
String::class -> getString(key, defaultValue as? String) as T?
Int::class -> getInt(key, defaultValue as? Int ?: -1) as T?
Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
else -> throw UnsupportedOperationException("Not yet implemented")
}
}

操作符重载 这里详细讲述了Kotlin中所有支持 operator 的操作符。

3. Tip

这篇文章讲了几个写Library的建议,感觉既可以作为Review 又可以作为Tips:

  • 文档
    一个好的Library一定要有一个好的文档

  • 专业
    Library应该做它应该具备的功能,而不是涵盖的范围越广越好,应让Library代码逻辑清晰并且能够准确的表达出功能。

  • 更加清晰和简洁的API设计
    函数应该只包含一件事请,同时函数名应该准确的描述函数功能并且没有任何歧义。例如作者举例应该使用ensureInitializedOrThrow() 代替 checkInit()

  • 防止用户滥用API
    Library应该提供适当的扩展对于用户。但是对于Library的访问权限也需要控制,对于不需要暴露的接口不应该暴露出去,对于不能够被继承的类使用final修饰。

  • 在必要的时候更新API
    更好的代码质量带来的好处要多过用户在更新代码库时遇到的麻烦

  • 谨慎使用自定义view
    自定义View应当在Library中谨慎使用,因为i自定义View可以找到很多不好的实现、hack以及碎片化。自定义View最大的问题就是它需要更多的灵活性和可自定义性。而这也带来了更多的不可控的因素。

  • 检查非法参数
    对于非法参数应该抛出对应的异常:

    Arguably, all erroneous method invocations boil down to an illegal argument or illegal state, but other exceptions are standardly used for certain kinds of illegal arguments and states. If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException. Similarly, if a caller passes an out-of-range value in a parameter representing an index into a sequence, IndexOutOfBoundsException should be thrown rather than IllegalArgumentException.

4. Share