可是写了很多垃圾代码,却只能在自己还会的地方练习,因为自己不会的地方几乎要熬夜去学(跑
准备继续写那个拖了很久的 TelegramMessageParser...
准备继续写那个拖了很久的 TelegramMessageParser...
#Java #Kotlin #JVM #CS #PL #dev 🤔
duangsuse 发现自己对 Java 在集合类里泛型问题的又有了新一层的理解。
为什么容器类需要用泛型?
因为肯定是希望
Java 里默认的泛型形变,是 Invarant(不变) 的
这种情况下,虽然我们知道 Cat 是 Animal,但是
如果我们要编写一个
在这里,根据 Java 的 PECS(Producer-Extends-Consumer-Super)原则,我们知道
但是为什么呢? 🤔
这里你只会了解到和程序设计语言类型有关的信息,Kotlin 的类型投影什么的不会讲。
—
泛型的『型变』是什么?
泛型的型变就是告诉 Java 类型检查器,一种泛型类的子类型关系,和它的参数化类型有什么样的联系。
这样,我们就可以实现类型安全的容器类泛化类型操作。
+ 协变(covariant):Cat 是 Animal,List<Cat> 也是 List<Animal>
+ 逆变(contravariant):Cat 是 Animal,List<Animal> (这时可能被用作输出) 是 List<Cat>
+ 不变:无论 Cat 是不是 Animal,List<Cat> 和 List<Animal> 之间没有太大的关系
在这里,子类型的『级别』,
有类型 P 是类型 C 的父类型,
Kotlin 里面,泛型的
有类型 P 是类型 C 的父类型,
其实我们想说,为了类型安全,
我们希望所有对象都的确实现了
所以,我们需要一个 producer —
反过来说,
PECS,我们知道现在该用
所以,当『输出到集合(使用
这样,output(装着某种
这就使用了泛型的逆变
duangsuse 发现自己对 Java 在集合类里泛型问题的又有了新一层的理解。
为什么容器类需要用泛型?
因为肯定是希望
List<Animal> 能够去 addAll(List<Cat>) 的呢。Java 里默认的泛型形变,是 Invarant(不变) 的
这种情况下,虽然我们知道 Cat 是 Animal,但是
List<Cat> 却和 List<Animal> 不存在子类型 subtyping 关系!如果我们要编写一个
addAll(??? other) 函数,保证类型安全(List<Cat> 显然不应该保存 List<Animal>!),并且让 Java 的类型检查器可以做检查的话,就必须指定泛型型变!在这里,根据 Java 的 PECS(Producer-Extends-Consumer-Super)原则,我们知道
addAll 的类型,显然应该是 void addAll(List<? extends T> input); 但是为什么呢? 🤔
这里你只会了解到和程序设计语言类型有关的信息,Kotlin 的类型投影什么的不会讲。
—
泛型的『型变』是什么?
泛型的型变就是告诉 Java 类型检查器,一种泛型类的子类型关系,和它的参数化类型有什么样的联系。
这样,我们就可以实现类型安全的容器类泛化类型操作。
+ 协变(covariant):Cat 是 Animal,List<Cat> 也是 List<Animal>
+ 逆变(contravariant):Cat 是 Animal,List<Animal> (这时可能被用作输出) 是 List<Cat>
+ 不变:无论 Cat 是不是 Animal,List<Cat> 和 List<Animal> 之间没有太大的关系
在这里,子类型的『级别』,
父类型为小子类型为大,以 lessThan 序排行,可能类似这样:1. Object(kotlin.Any)Kotlin 里面,泛型的
2. Animal
3. Cat
in T 指定了可取类型的下界 — 可选类型 ? 必须是 super T(T 的超类)才可以,而 Animal 的确 super 了 Cat,所以可取类型必须 (lessThan Cat)
它实现了泛型的逆变 —有类型 P 是类型 C 的父类型,
P lessThan C
类型 F<? super C> 是 F<P> 的父类型 (_<P> lessThan _<? lessThan C>)Kotlin 里面,泛型的
out T 指定了可取类型集合的上界 — 可取类型 ? 必须是 extends T(T 的子类型)才可以,而 Cat 的确 extends from 了 Animal,所以可取类型必须 (greaterThan Animal)
它实现了泛型的协变 —有类型 P 是类型 C 的父类型,
P lessThan C
类型 F<? extends C> 是 F<P> 的子类型 (_<P> greaterThan _<? greaterThan C>)其实我们想说,为了类型安全,
List<Animal> 的容器里,可以放的东西类型应该是:? extends Animal
也可以说是 ? greaterThan Animal,反正比 Animal 能就可以了(跑)我们希望所有对象都的确实现了
Animal(可以装 Animal 和它的子类扩充)所以,我们需要一个 producer —
List<? extends Animal> 来喂数据,进行 addAll 操作(利用一个 Iterable<T>,这里 T 就肯定是某种 Animal, 或者说我们利用 T get(); 方法肯定会拿到 Animal)反过来说,
popAll 呢?PECS,我们知道现在该用
in T 了 🤔fun popAll(output: Collection<in T>): Unit
或者说,void popAll(Collection<? super T> output);我们不希望任何容器,包括
output 被放上不好的东西(某种不是 Animal 的东西!)所以,当『输出到集合(使用
void add(T item); 方法)』的时候,不如反转一下子类型关系!(相对于 addAll)这样,output(装着某种
T) 就只会被 add 上一些 extends T 的东西(这个类型自己),保证了类型安全这就使用了泛型的逆变
duangsuse::Echo
非常的难受,但这居然还比 Gradle、CMake 要简单一点?(可能不是
看了一下 IDEA 的 #Java 语言版本提示,我默写一下:
1.3: Plain Old Java (2000)
1.4:
5: Autoboxing,
6:
7: ARM, Diamond, multi-catch (2011)
8: Lambda and Type annotations (2013)
9: Modules,
10: Local variable inference (2018)
11: Local variable syntax for lambda parameters (2018)
没有成功,但是也快了,只是 Java 7 的默写错了,别的有漏的。
啊,提起 Java,这门『垃圾』语言(和 CSharp、Kotlin、Rust 等相比就是垃圾了,差一点没 Julia、R、Fortran 之类的厉害?'跑,,,,),也未必是被大部分人完全理解的呢。
那么我们今天来完全理解一下,自 1995 年从 Oak 更名,1997 年的 Java 1.1 开始,之间提到 2004 年语法糖飞跃的 Java 5,再到最近 2018 年的 Java 11 结束,我们会看到所有的 Java 语法。(其实语法上的已经足够浅层次了,但是即使这样,很多人都能注意到自己没见过的 Java 语法)
当然,定义什么的冗长(好歹 James 老头子也是博士学位啊!)所以得感谢 ANTLR
🤔 #Learn #PL #OOP
1.3: Plain Old Java (2000)
1.4:
assert keyword (2002)5: Autoboxing,
enum, generics (2004)6:
@Override in interfaces (2006)7: ARM, Diamond, multi-catch (2011)
8: Lambda and Type annotations (2013)
9: Modules,
private fields in interfaces (2017)10: Local variable inference (2018)
11: Local variable syntax for lambda parameters (2018)
没有成功,但是也快了,只是 Java 7 的默写错了,别的有漏的。
啊,提起 Java,这门『垃圾』语言(和 CSharp、Kotlin、Rust 等相比就是垃圾了,差一点没 Julia、R、Fortran 之类的厉害?'跑,,,,),也未必是被大部分人完全理解的呢。
那么我们今天来完全理解一下,自 1995 年从 Oak 更名,1997 年的 Java 1.1 开始,之间提到 2004 年语法糖飞跃的 Java 5,再到最近 2018 年的 Java 11 结束,我们会看到所有的 Java 语法。(其实语法上的已经足够浅层次了,但是即使这样,很多人都能注意到自己没见过的 Java 语法)
当然,定义什么的冗长(好歹 James 老头子也是博士学位啊!)所以得感谢 ANTLR
🤔 #Learn #PL #OOP
GitHub
sdklite/aapt
Android Asset Packaging Tool. Contribute to sdklite/aapt development by creating an account on GitHub.
duangsuse::Echo
看了一下 IDEA 的 #Java 语言版本提示,我默写一下: 1.3: Plain Old Java (2000) 1.4: assert keyword (2002) 5: Autoboxing, enum, generics (2004) 6: @Override in interfaces (2006) 7: ARM, Diamond, multi-catch (2011) 8: Lambda and Type annotations (2013) 9: Modules, private fields…
This media is not supported in your browser
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Forwarded from 羽毛的小白板
不是一个人(这个真的是极品!)。不是一个人,实际上很多工程师都这么做... 讲道理,我觉得他们应该去学学 parser combinator style parsers...
再说,就是 Java 也提供了 XML 解析库啊(Simple Api for Xml)... HTML 的也不难找,至于写爬虫什么的也可以说是必须品,除了一些情况有些人会利用 regex 之外,正规的做法是 dom parser + XPath / CSS Selector. 基本都是这样的,Ruby 的话,创建 HTML 可以用 Builder,解析可以用 Nokogiri.
再说,就是 Java 也提供了 XML 解析库啊(Simple Api for Xml)... HTML 的也不难找,至于写爬虫什么的也可以说是必须品,除了一些情况有些人会利用 regex 之外,正规的做法是 dom parser + XPath / CSS Selector. 基本都是这样的,Ruby 的话,创建 HTML 可以用 Builder,解析可以用 Nokogiri.
GitHub
bangarharshit/Gradle-Layout-Formatter
Gradle plugin for formatting android layout files. Contribute to bangarharshit/Gradle-Layout-Formatter development by creating an account on GitHub.
This media is not supported in your browser
VIEW IN TELEGRAM
我思量着他们写出那么多看起来高大上的代码为什么会不会写解析器.... 很困难么?
大概是应用层的东西做多了,我看到
看看复杂的控制结构,结果发现其实是不良实践... 我觉得我就是想分析得太深了,不需要测试数据就根据程序乱猜?
大概是应用层的东西做多了,我看到
++n、Integer.MAX_VALUE 这种代码和一些 Provider 模式都开始觉得高大上...看看复杂的控制结构,结果发现其实是不良实践... 我觉得我就是想分析得太深了,不需要测试数据就根据程序乱猜?
https://github.com/by-syk/SP
🤔 现在想起来,其实如果能进行快速的工程的话,就可以写出很多这种封装库。
可惜只有下周了,这周还有 BinaryStreamIO 和 SimpleCat
🤔 现在想起来,其实如果能进行快速的工程的话,就可以写出很多这种封装库。
可惜只有下周了,这周还有 BinaryStreamIO 和 SimpleCat
SharedPreferences sharedPreferences = context.getSharedPreferences(context这是 Android 的 SharePreference 裸 API
.getPackageName(), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("user", "By_syk");
editor.apply();
SP sp = new SP(context);如果使用 SharedPreferenceProxy,你可以在 Android 上用面向接口编程,节省自己的时间:
// Create and Update
sp.save("user", "By_syk");
sp.put("num", 5)
.put("valid", true)
.save();
// Read
String user = sp.getString("user");
// Delete
sp.delete("user");
sp.remove("num")
.remove("valid")
.save();
@AndroidPreference(private = true, name = USE_PACKAGE_NAME, naming = NamingStrategy.SNACK_CASED)
interface ApplicationPreference {
String getUser();
void setUser(String value);
PreferenceTransactionBuilder user(String newValue);
}
然后PreferenceProxy cfg = new PreferenceProxy(ApplicationPreference.class);
接着就可以:// Create (map like)
cfg.put("name", "value object");
cfg
.make("name1", "value1")
.commit();
cfg
.update("name1", "value2")
.commit();
// Update
cfg.setUser("duangsuse");
// Read
cfg.getUser(); //=> "duangsuse"
cfg.get("user"); //=> "duangsuse"
// Delete
cfg.delete("user");
cfg
.purge("user")
.commit();GitHub
by-syk/SP
Using android.content.SharedPreferences simply. Contribute to by-syk/SP development by creating an account on GitHub.
duangsuse::Echo
https://github.com/by-syk/SP 🤔 现在想起来,其实如果能进行快速的工程的话,就可以写出很多这种封装库。 可惜只有下周了,这周还有 BinaryStreamIO 和 SimpleCat SharedPreferences sharedPreferences = context.getSharedPreferences(context .getPackageName(), Context.MODE_PRIVATE); SharedPreferences.Editor editor…
GitHub
duangsuse-valid-projects/telegramscanner
Telegram Message stream scanner java library. Contribute to duangsuse-valid-projects/telegramscanner development by creating an account on GitHub.
duangsuse::Echo
https://github.com/by-syk/SP 🤔 现在想起来,其实如果能进行快速的工程的话,就可以写出很多这种封装库。 可惜只有下周了,这周还有 BinaryStreamIO 和 SimpleCat SharedPreferences sharedPreferences = context.getSharedPreferences(context .getPackageName(), Context.MODE_PRIVATE); SharedPreferences.Editor editor…
总的来说,PreferencePrxoy 要有以下方法(类似,因为要有特殊类型的重载):
== Read
不打算提供其他的函数式接口,存储方式可能是 Java serializable
== Read
PreferencePrxoy#get(String):Any== Create
PreferencePrxoy#contains(String):Boolean
PreferenceTransactionBuilder#make(String, Any):PreferenceTransactionBuilder== Update
PreferenceTransactionBuilder#ensure(String, Any):PreferenceTransactionBuilder
PreferenceProxy#set(String, Any):Unit== Delete
PreferenceTransactionBuilder#update(String, Any):PreferenceTransactionBuilder
PreferenceProxy#put(String, Any):PreferenceProxy
PreferenceTransactionBuilder#purge(String):Unit
PreferenceProxy#delete(String):Any
PreferenceProxy#remove(String):PreferenceProxy
PreferenceProxy#destroy():Unit
最后,它要识别 interface 里的 Getter、Setter、Transaction interface,并且检查附属的 annotation(对于整个 Preference,要指定名称和可见性以及属性命名方式,对于字段可能要指定自己的属性名、存储方式)不打算提供其他的函数式接口,存储方式可能是 Java serializable
ObjectOutputStream + Base64 或者 JSON
为了使得库接口更加可移植,使用的 Preference 必须只是一个接口(能完成提供 API 的),实际实现使用 Delegate,这样可以兼容更多的底层存储系统