diff --git a/README.md b/README.md index 00d41da..cdb2a9b 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,12 @@ **为开源贡献自己的一份力量。** -## :blue_book: [JVM 篇](/jvm) +**欢迎关注个人公众号,每天更新原创技术好文**: +![Tommy 学习录](./img/tommy学习录.png) -## :coffee: [Java8 篇](/java8) +## :blue_book: [JVM 篇](/jvm) -## :house_with_garden: [数据结构篇](/datastructure) -- [StringBuilder和StringBuffer](/datastructure/stringbuilderandstringbuffer.md) -- [BlockingQueue和BlockingDeque](/datastructure/blockingqueueanddeque.md) - * Queue - * Deque - * LinkedList - * ArrayBlockingQueue - * LinkedBlockingQueue - * LinkedBlockingDeque +## :coffee: [Java 基础知识篇](/javabase) ## :scroll: [代码篇](/codeinterview) 主要介绍 LeetCode 上面的算法题目,以及面试过程中遇到的实际编码问题总结。 @@ -43,11 +36,9 @@ ## :computer: [大数据篇](/bigdata) -## :floppy_disk: [架构篇](/architecture) +## :earth_asia: [机器学习](/machinelearning) -## :abcd: [关键字篇](/keywords) -- [transient](/keywords/transient.md) -- [volatile](/keywords/volatile.md) +## :floppy_disk: [架构篇](/architecture) ## :earth_asia: [web 篇](/web) @@ -64,7 +55,3 @@ 有什么问题也可以在这里进行[讨论](https://github.com/joyang1/JavaInterview/issues/1)。 -**欢迎关注个人公众号,每天更新原创技术好文**: - -![](mymp.jpeg) - diff --git a/architecture/README.md b/architecture/README.md index 5790b43..0133378 100644 --- a/architecture/README.md +++ b/architecture/README.md @@ -1,7 +1,12 @@ # 架构篇 +## UML图 +分享项目设计中需要的类图、对象图、时序图等。
+[UML图总结](uml.md) + ## 设计模式 -分享实际项目中的设计模式经验 +分享实际项目中的设计模式经验。
+[设计模式](design_patterns.md) ## 分布式 @@ -23,3 +28,12 @@ - [MySQL](mysql.md) - [Redis](redis.md) - [ElasticSearch](elasticSearch.md) +- MongoDB + +## 大数据 +- Hadoop +- Hive +- Spark + +## 推荐系统 +- [推荐系统](recommend_system.md) diff --git a/architecture/design_patterns.md b/architecture/design_patterns.md new file mode 100644 index 0000000..6a37917 --- /dev/null +++ b/architecture/design_patterns.md @@ -0,0 +1,177 @@ +# 设计模式 +该章节主要是在读《Head First 设计模式》的总结。 + +## 策略模式 +案例:鸭子应用(模拟鸭子游戏)。 +游戏中需要设计各种鸭子,有戏水的、呱呱叫的。用学习过的OO技术,张三(鸭子游戏"首席架构师")首先会设计一个鸭子超类,并让各种鸭子继承该超类。 +![OO类图1](https://cdn.jsdelivr.net/gh/filess/img10@main/2021/04/06/1617640082714-8a14a0d7-73d1-471a-893f-a94fe3a5966f.jpg) + +类图中,超类Duck实现了鸭子呱呱叫(quack)和游泳(swim),由于鸭子外观都不同,所以display()方法是抽象的,由子类去实现。 +具体代码在该项目的位置:JavaInterview/architecture/src/main/java/cn.tommyyang.designpatterns.duckgame.Duck。 + +以上完成第一版鸭子应用。 + +由于鸭子游戏鸭子种类一直就那么几种,导致游戏用户增长上遇到了较大的瓶颈,所以急需创新。通过大家的头脑风暴,首先我们得让鸭子飞起来。这时,负责鸭子应用的开发人员张三接到了这个需求,认为只需在Duck超类上加上fly方法即可。设计如下: +![OO类图2](https://cdn.jsdelivr.net/gh/filess/img16@main/2021/04/06/1617640156038-1a4f4a43-5071-4ca9-a1a9-055d154629cd.jpg) + +改完后,完成了游戏的第二次发版。改动点: +- 加入鸭子会飞的逻辑。 +- 有鸭子的叫声不是呱呱叫,而是吱吱叫。 + +发布完成后,在公司内部开始进行试运行。试运行期间,同事们说,为什么橡皮鸭也会飞啊。张三收到了反馈后,他发现出问题了,不能直接在超类进行fly()方法的实现,或者在橡皮鸭内部覆盖fly方法,然后什么都不做。 +如果后面有几万种鸭子,比如加入了诱饵鸭(是木头鸭),不会飞也不会叫,那怎么办,也去覆盖quack、fly方法?那这样继承这些方法有什么意义呢? +看到这里,不知道大家怎么想? + +首先总结下利用继承来提供Duck的行为会导致哪些缺点: +- 代码在多个子类中重复。 +- 运行时的行为不容易改变。 +- 不能让鸭子跳舞。 +- 很难知道所有鸭子的全部行为。 +- 鸭子不能同时又飞又叫。 +- 改变会牵一发动全身,造成其他鸭子不想要的改变。 + +通过在游戏的第二版发布过程中,张三认识到继承无法解决在当下游戏版本经常更新的情况。张三知道鸭子的规则会经常改变,每当游戏中新增新的鸭子时,就需要检查是否需要覆盖fly()/quack()......等方法,张三作为"首席架构师",显然觉得这样的架构太low了,无法容忍。 + +故张三认为需要定义一些更清晰的接口,让"某些"(非全部)鸭子类型可飞/可叫......以后还可能扩展更多方法。 +新的架构图如下: +![接口类图1](https://cdn.jsdelivr.net/gh/filess/img6@main/2021/04/06/1617640189105-a5fc6182-7ad7-41d1-be45-d88e3e642903.jpg) + +以上是张三使用接口实现的,但是张三对着类图思考了一会,发现虽然Flyable和Quackable可以解决"一小部分"问题(不会出现会飞的橡皮鸭),但是却造成了大量重复代码(大量的重复飞,重复嘎嘎叫),但代码却无法复用,甚至,在会飞的鸭子中,飞行的动作还可能各种变化...... + +作为"首席架构师",张三还是觉得否定了上述方案,深思许久后,总结道: +- 继承无法解决问题。 +- Flyable、Quackable接口不错,但是需要让会飞的鸭子才继承Flybale。 +- Java接口不具有实现代码(java8 default接口可以,但是不鼓励使用),所以继承接口无法达到代码的复用。 + +这时,张三突然想到从《Head First 设计模式》中看到的第一个设计模式中提到的三个原则: +- 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。 +- 针对接口编程,而不是针对实现编程。 +- 多用组合,少用继承。 + +通过上述三个原则,张三知道,Duck类中fly()和quack()会随着鸭子的不同而改变。那么需要把这两个行为从Duck类中取出来,建立一组新类来代表每个行为。及游戏中需要**鸭子类**和`鸭子行为类`。`鸭子行为类`专门用于提供某行为接口的实现,那么鸭子类就不需要了解行为的实现细节了。这就是`针对接口编程,而不是针对实现编程`。 + +了解到这些设计原则后,张三开始重新设计类图。 +![策略模式类图](https://cdn.jsdelivr.net/gh/filess/img16@main/2021/04/06/1617640242705-5b21c883-4753-46b4-8aab-885fe5be2894.jpg) + +通过以上设计,关键在于,鸭子将飞行和呱呱叫的动作"委托"(delegate)别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法。 +这样的好处,就是上述的三个原则,并且在运行时,可以随意修改其呱呱叫和飞行的行为,通过setFlyBehavior和setQuackBehavior来实现。 + +MallardDuck 的具体实现如下: + +``` java + +/** + * 野鸭类 + * + * @Author : TommyYang + * @Time : 2021年04月05日 16:00 + * @Software: IntelliJ IDEA + * @File : MallardDuck.java + */ +public class MallardDuck extends Duck { + + public MallardDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) { + super(flyBehavior, quackBehavior); + } + + /** + * 具体实现鸭子外观 + */ + public void display() { + System.out.println("绿头"); + } +} + +``` + +在构造野鸭类的时候,完成 FlyBehavior 和 QuackBehavior 的定义。 + +最后,张三"首席架构师",通过`策略模式(Strategy Pattern)`实现了鸭子游戏。 + +`策略模式`定义了算法簇,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。 + +恭喜你,完成了第一个设计模式`策略模式`的学习,后续希望该模式在你的编程生涯中可以持续被使用。 + +## 观察者模式 +张三由于通过使用`策略模式`完成鸭子游戏应用的重构后,在鸭子游戏的维护和更新上只需要投入少量的时间。 +于是张三接到了下一个需求,*互联网气象观测站*的架构工作。 + +*互联网气象观测站*的三个组成部分: +- 气象站(获得实际气象数据的物理装置) +- WeatherData 对象(追踪来自气象站的数据,并更新布告板) +- 布告板(显示当前天气状况)给用户看 + +张三总结出系统用例如下: + +张三认为,如果团队接受了这个项目,那工作就是建立一个应应用,利用 WeatherData 对象取得数据(由公司兄弟团队去和气象站对接),并更新三个布告板:当前状况、气象统计、天气预报。 + +张三团队开始了工作,第二天由公司兄弟团队提供的获取相关气象数据的 WeatherData 类,类图如下: + +下面看一下实现的反面案例:针对具体实现编程。 +具体代码在该项目的位置:[JavaInterview](https://github.com/joyang1/JavaInterview); +JavaInterview/architecture/src/main/java/cn.tommyyang.designpatterns.observable.WeatherData。 + +```java + +public class WeatherData { + /** + * 温度 + */ + private float temperature; + + /** + * 湿度 + */ + private float humidity; + + /** + * 气压 + */ + private float pressure; + + public float getTemperature() { + return this.temperature; + } + + public float getHumidity() { + return this.humidity; + } + + public float getPressure() { + return pressure; + } + + /** + * 一旦气象测量更新,此方法会被调用 + */ + public void measurementsChanged() { + float temp = getTemperature(); + float humidity = getHumidity(); + float pressure = getPressure(); + + // 布告板数据更新 + // 针对具体的实现编程,导致后续增删布告板时必须修改程序 + CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(); + currentConditionsDisplay.update(temp, humidity, pressure); + } +} + +``` +回故下上一篇讲解的一些设计原则: +- 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。 +- 针对接口编程,而不是针对实现编程。 +- 多用组合,少用继承。 + +不难发现上面的代码非常*垃圾*。 + +下面由首席架构师张三带大家使用观察者模式来实现该工程。 + +`观察者模式`:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 +张三画了一张简易的观察者模式图如下: + +## 装饰模式 + +## 工厂模式 +### 简单工厂模式 + +### 工厂方法模式 \ No newline at end of file diff --git a/architecture/img/aggregation.png b/architecture/img/aggregation.png new file mode 100644 index 0000000..3ab02c7 Binary files /dev/null and b/architecture/img/aggregation.png differ diff --git a/architecture/img/association.png b/architecture/img/association.png new file mode 100644 index 0000000..96068ad Binary files /dev/null and b/architecture/img/association.png differ diff --git a/architecture/img/combine.png b/architecture/img/combine.png new file mode 100644 index 0000000..b5f64f4 Binary files /dev/null and b/architecture/img/combine.png differ diff --git a/architecture/img/depend.png b/architecture/img/depend.png new file mode 100644 index 0000000..457ad2a Binary files /dev/null and b/architecture/img/depend.png differ diff --git a/architecture/img/extends.png b/architecture/img/extends.png new file mode 100644 index 0000000..e0fb4c1 Binary files /dev/null and b/architecture/img/extends.png differ diff --git a/architecture/img/implement.png b/architecture/img/implement.png new file mode 100644 index 0000000..9057c45 Binary files /dev/null and b/architecture/img/implement.png differ diff --git a/architecture/img/uml-class-animal.jpg b/architecture/img/uml-class-animal.jpg new file mode 100644 index 0000000..fd38c89 Binary files /dev/null and b/architecture/img/uml-class-animal.jpg differ diff --git a/architecture/img/uml-object.jpg b/architecture/img/uml-object.jpg new file mode 100644 index 0000000..3d165eb Binary files /dev/null and b/architecture/img/uml-object.jpg differ diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/Duck.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/Duck.java new file mode 100644 index 0000000..dc55e99 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/Duck.java @@ -0,0 +1,70 @@ +package cn.tommyyang.designpatterns.duckgame; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * 鸭子超类(抽象类) + * + * @Author : TommyYang + * @Time : 2021年04月05日 15:57 + * @Software: IntelliJ IDEA + * @File : Duck.java + */ +public abstract class Duck { + + public Duck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) { + this.flyBehavior = flyBehavior; + this.quackBehavior = quackBehavior; + } + + /** + * 名称 + */ + private String name; + + /** + * 飞行行为 + */ + private FlyBehavior flyBehavior; + + /** + * 呱呱叫行为 + */ + private QuackBehavior quackBehavior; + + /** + * 鸭子的叫声 + */ + public void performQuack() { + this.quackBehavior.quack(); + } + + /** + * 鸭子游泳 + */ + public void swim() { + System.out.println("游泳"); + } + + + /** + * 执行飞行行为 + */ + public void performFly() { + this.flyBehavior.fly(); + } + + /** + * 鸭子外观都不相同,所以设计为抽象方法 + */ + public abstract void display(); + + public void setFlyBehavior(FlyBehavior flyBehavior) { + this.flyBehavior = flyBehavior; + } + + public void setQuackBehavior(QuackBehavior quackBehavior) { + this.quackBehavior = quackBehavior; + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MainExecutor.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MainExecutor.java new file mode 100644 index 0000000..ac5502c --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MainExecutor.java @@ -0,0 +1,43 @@ +package cn.tommyyang.designpatterns.duckgame; + +import cn.tommyyang.designpatterns.duckgame.Duck; +import cn.tommyyang.designpatterns.duckgame.RubberDuck; +import cn.tommyyang.designpatterns.duckgame.WoodDuck; +import cn.tommyyang.designpatterns.duckgame.behavior.impl.FlyWithNoWay; +import cn.tommyyang.designpatterns.duckgame.behavior.impl.MuteQuack; +import cn.tommyyang.designpatterns.duckgame.behavior.impl.Squeak; + +/** + * 鸭子游戏执行器 + * + * @Author : TommyYang + * @Time : 2021年04月05日 16:00 + * @Software: IntelliJ IDEA + * @File : MainExecutor.java + */ +public class MainExecutor { + + public static void main(String[] args) { + + // 实现不能飞行的橡皮鸭 + RubberDuck rubberDuck = new RubberDuck(new FlyWithNoWay(), new Squeak()); + execute(rubberDuck); + + // 实现不能飞也不能叫的橡皮鸭 + WoodDuck woodDuck = new WoodDuck(new FlyWithNoWay(), new MuteQuack()); + execute(woodDuck); + + // 后续各种鸭子实现,根据业务方的需求,设置其行为即可,行为可扩展,可复用 + // 这就是"策略模式",各种策略实现好,组合使用即可 + } + + + /** + * 鸭子游戏开始运行 + */ + private static void execute(Duck duck) { + duck.display(); + duck.performQuack(); + duck.performFly(); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MallardDuck.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MallardDuck.java new file mode 100644 index 0000000..0bc89f2 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/MallardDuck.java @@ -0,0 +1,29 @@ +package cn.tommyyang.designpatterns.duckgame; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * 野鸭类 + * + * @Author : TommyYang + * @Time : 2021年04月05日 16:00 + * @Software: IntelliJ IDEA + * @File : MallardDuck.java + */ +public class MallardDuck extends Duck { + + /** + * 构造器 + */ + public MallardDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) { + super(flyBehavior, quackBehavior); + } + + /** + * 具体实现鸭子外观 + */ + public void display() { + System.out.println("绿头"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RedheadDuck.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RedheadDuck.java new file mode 100644 index 0000000..999f6b2 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RedheadDuck.java @@ -0,0 +1,28 @@ +package cn.tommyyang.designpatterns.duckgame; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * 红头鸭 + * + * @Author : TommyYang + * @Time : 2021年04月05日 16:02 + * @Software: IntelliJ IDEA + * @File : RedheadDuck.java + */ +public class RedheadDuck extends Duck { + /** + * 构造器 + */ + public RedheadDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) { + super(flyBehavior, quackBehavior); + } + + /** + * 具体实现鸭子外观 + */ + public void display() { + System.out.println("红头"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RubberDuck.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RubberDuck.java new file mode 100644 index 0000000..08b9ed1 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/RubberDuck.java @@ -0,0 +1,28 @@ +package cn.tommyyang.designpatterns.duckgame; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * 橡皮鸭 + * + * @Author : TommyYang + * @Time : 2021年04月05日 16:17 + * @Software: IntelliJ IDEA + * @File : RubberDuck.java + */ +public class RubberDuck extends Duck { + /** + * 构造器 + */ + public RubberDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) { + super(flyBehavior, quackBehavior); + } + + /** + * 具体实现鸭子外观 + */ + public void display() { + System.out.println("橡皮鸭"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/WoodDuck.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/WoodDuck.java new file mode 100644 index 0000000..e620fef --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/WoodDuck.java @@ -0,0 +1,26 @@ +package cn.tommyyang.designpatterns.duckgame; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * @Author : TommyYang + * @Time : 2021年04月10日 22:23 + * @Software: IntelliJ IDEA + * @File : WoodDuck.java + */ +public class WoodDuck extends Duck { + /** + * 构造器 + */ + public WoodDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) { + super(flyBehavior, quackBehavior); + } + + /** + * 木头鸭外观 + */ + public void display() { + System.out.println("木头鸭"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/FlyBehavior.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/FlyBehavior.java new file mode 100644 index 0000000..28f878d --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/FlyBehavior.java @@ -0,0 +1,18 @@ +package cn.tommyyang.designpatterns.duckgame.behavior; + +/** + * 鸭子飞行行为接口 + * + * @Author : TommyYang + * @Time : 2021年04月06日 00:10 + * @Software: IntelliJ IDEA + * @File : FlyBehavior.java + */ +public interface FlyBehavior { + + /** + * 定义飞行方法 + */ + void fly(); + +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/QuackBehavior.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/QuackBehavior.java new file mode 100644 index 0000000..c1880c7 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/QuackBehavior.java @@ -0,0 +1,18 @@ +package cn.tommyyang.designpatterns.duckgame.behavior; + +/** + * 鸭子呱呱叫行为接口 + * + * @Author : TommyYang + * @Time : 2021年04月06日 00:10 + * @Software: IntelliJ IDEA + * @File : QuackBehavior.java + */ +public interface QuackBehavior { + + /** + * 定义呱呱叫方法 + */ + void quack(); + +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithNoWay.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithNoWay.java new file mode 100644 index 0000000..35280ca --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithNoWay.java @@ -0,0 +1,21 @@ +package cn.tommyyang.designpatterns.duckgame.behavior.impl; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; + +/** + * 不能飞行行为定义 + * + * @Author : TommyYang + * @Time : 2021年04月10日 22:16 + * @Software: IntelliJ IDEA + * @File : FlyWithNoWay.java + */ +public class FlyWithNoWay implements FlyBehavior { + /** + * 不能飞行行为实现 + */ + @Override + public void fly() { + System.out.println("no way to fly"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWay.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWay.java new file mode 100644 index 0000000..fcf0bd8 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWay.java @@ -0,0 +1,21 @@ +package cn.tommyyang.designpatterns.duckgame.behavior.impl; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; + +/** + * 实现飞行方法 + * + * @Author : TommyYang + * @Time : 2021年04月07日 23:23 + * @Software: IntelliJ IDEA + * @File : FlyWithWay.java + */ +public class FlyWithWay implements FlyBehavior { + /** + * 实现飞行行为 + */ + @Override + public void fly() { + System.out.println("fly with way"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWings.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWings.java new file mode 100644 index 0000000..2918389 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/FlyWithWings.java @@ -0,0 +1,21 @@ +package cn.tommyyang.designpatterns.duckgame.behavior.impl; + +import cn.tommyyang.designpatterns.duckgame.behavior.FlyBehavior; + +/** + * 通过翅膀飞行实现类 + * + * @Author : TommyYang + * @Time : 2021年04月07日 23:21 + * @Software: IntelliJ IDEA + * @File : FlyWithWings.java + */ +public class FlyWithWings implements FlyBehavior { + /** + * 实现飞行行为 + */ + @Override + public void fly() { + System.out.println("fly with wings"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/MuteQuack.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/MuteQuack.java new file mode 100644 index 0000000..0e6d65c --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/MuteQuack.java @@ -0,0 +1,21 @@ +package cn.tommyyang.designpatterns.duckgame.behavior.impl; + +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * @Author : TommyYang + * @Time : 2021年04月09日 22:31 + * @Software: IntelliJ IDEA + * @File : MuteQuack.java + */ +public class MuteQuack implements QuackBehavior { + /** + * 实现 quack 方式 + * 不能叫 + */ + @Override + public void quack() { + // nothing + System.out.println("no quack"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Quack.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Quack.java new file mode 100644 index 0000000..1ce977d --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Quack.java @@ -0,0 +1,19 @@ +package cn.tommyyang.designpatterns.duckgame.behavior.impl; + +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * @Author : TommyYang + * @Time : 2021年04月09日 22:29 + * @Software: IntelliJ IDEA + * @File : Quack.java + */ +public class Quack implements QuackBehavior { + /** + * 实现 quack 方式 + */ + @Override + public void quack() { + System.out.println("呱呱叫"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Squeak.java b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Squeak.java new file mode 100644 index 0000000..010ef06 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/duckgame/behavior/impl/Squeak.java @@ -0,0 +1,19 @@ +package cn.tommyyang.designpatterns.duckgame.behavior.impl; + +import cn.tommyyang.designpatterns.duckgame.behavior.QuackBehavior; + +/** + * @Author : TommyYang + * @Time : 2021年04月09日 22:30 + * @Software: IntelliJ IDEA + * @File : Squeak.java + */ +public class Squeak implements QuackBehavior { + /** + * 实现 quack 方式 + */ + @Override + public void quack() { + System.out.println("吱吱叫"); + } +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/observable/WeatherData.java b/architecture/src/main/java/cn/tommyyang/designpatterns/observable/WeatherData.java new file mode 100644 index 0000000..35ae682 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/observable/WeatherData.java @@ -0,0 +1,56 @@ +package cn.tommyyang.designpatterns.observable; + +import cn.tommyyang.designpatterns.observable.display.CurrentConditionsDisplay; + +/** + * 观察者模式 + * WeatherData 类 + * + * @Author : TommyYang + * @Time : 2021年04月18日 15:51 + * @Software: IntelliJ IDEA + * @File : WeatherData.java + */ +public class WeatherData { + /** + * 温度 + */ + private float temperature; + + /** + * 湿度 + */ + private float humidity; + + /** + * 气压 + */ + private float pressure; + + public float getTemperature() { + return this.temperature; + } + + public float getHumidity() { + return this.humidity; + } + + public float getPressure() { + return pressure; + } + + /** + * 一旦气象测量更新,此方法会被调用 + */ + public void measurementsChanged() { + float temp = getTemperature(); + float humidity = getHumidity(); + float pressure = getPressure(); + + // 布告板数据更新 + // 针对具体的实现编程,导致后续增删布告板时必须修改程序 + CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(); + currentConditionsDisplay.update(temp, humidity, pressure); + } + +} diff --git a/architecture/src/main/java/cn/tommyyang/designpatterns/observable/display/CurrentConditionsDisplay.java b/architecture/src/main/java/cn/tommyyang/designpatterns/observable/display/CurrentConditionsDisplay.java new file mode 100644 index 0000000..f10a615 --- /dev/null +++ b/architecture/src/main/java/cn/tommyyang/designpatterns/observable/display/CurrentConditionsDisplay.java @@ -0,0 +1,15 @@ +package cn.tommyyang.designpatterns.observable.display; + +/** + * @Author : TommyYang + * @Time : 2021年04月18日 16:00 + * @Software: IntelliJ IDEA + * @File : CurrentConditionsDisplay.java + */ +public class CurrentConditionsDisplay { + + public void update(float temp, float humidity, float pressure) { + + } + +} diff --git a/architecture/uml.md b/architecture/uml.md new file mode 100644 index 0000000..60fc393 --- /dev/null +++ b/architecture/uml.md @@ -0,0 +1,57 @@ +# UML 图总结 +## UML 类图 +> 描述类、接口、协作及他们之间的关系的图。显示系统中类的静态结构。 + +### 有什么作用? +描述软件系统的静态结构 +- 对系统的词汇建模 +- 对简单协作建模 +- 对逻辑数据库模式建模 + +### 类图说明 +> 类名为斜体则为抽象类
类方法为斜体则为抽象方法

第一行:类名称
第二行:类属性
第三行:类方法

类/属性/方法说明:
'-' 表示私有(private)
'#'表示保护(protected)
'+'表示公开(public) + + + +### 依赖关系 +> `虚线箭头`表示。 + + + + +### 继承关系 +> `实线空心三角形箭头`表示。 + + + +### 实现关系 +> `虚线空心三角形箭头`表示。 + + + +### 关联关系 +> `实线`表示。 + + + +### 组合关系 +> `实线黑色菱形箭头`表示。 + + + +### 聚合关系 +> `实线空心菱形箭头`表示。 + + + +## UML 对象图 +> 显示了某一时刻的一组对象及它们之间的关系。对象图可被看作是类图的实例,用来表达各个对象在某一时刻的状态。 + + + +### 对象图说明 +> stu 实例名称,Student 所属类。
第一行:对象名称
第二行:实例属性具体值 + +- stu:Student 标准表示法 +- :Student 匿名表示法 +- stu 省略类名表示法 \ No newline at end of file diff --git a/bigdata/hadoop.md b/bigdata/hadoop.md index 55bc9c2..607ec19 100644 --- a/bigdata/hadoop.md +++ b/bigdata/hadoop.md @@ -8,6 +8,19 @@ ## HDFS ## MapReduce +MapReduce是一种用于大规模数据处理的编程模型和计算框架。它被广泛应用于分布式系统中,旨在提供高效、可扩展和可靠的数据处理解决方案。 + +MapReduce的核心思想是将大规模数据集分成小的数据块,然后并行处理这些数据块。这个过程包括两个主要阶段:Map阶段和Reduce阶段。 + +在Map阶段,数据集被划分成多个小的输入块,每个输入块由一个Map任务处理。Map任务将输入块转换成键值对的集合。键值对的生成是通过应用用户自定义的Map函数来实现的。这个函数将输入数据转换成一个或多个键值对,其中键表示数据的特定属性,值则包含与该键相关联的信息。 + +在Reduce阶段,Map任务生成的键值对集合被分组和排序,然后传递给Reduce任务进行处理。Reduce任务的数量通常与计算集群中的处理节点数量相匹配。Reduce任务将相同键的键值对进行合并、计算和聚合操作,生成最终的输出结果。Reduce函数也是用户自定义的,根据需要执行各种操作,例如求和、计数、平均值等。 + +MapReduce的优点在于它的并行性和可伸缩性。通过将数据划分成小块并将其分发给多个处理节点进行并行处理,MapReduce可以有效地处理大规模数据集,提高处理速度和性能。此外,它提供了自动处理故障和容错的机制,保证了计算的可靠性。 + +MapReduce在分布式系统中得到了广泛应用。它是Apache Hadoop框架的核心组件之一,被用于处理大数据和进行复杂的数据分析任务。MapReduce还可以在其他领域中发挥作用,如搜索引擎、机器学习和图形处理等。 + +总而言之,MapReduce是一种强大的编程模型和计算框架,通过将大规模数据集划分成小块并在分布式环境中并行处理,提供了高效、可扩展和可靠的数据处理解决方案。它在大数据领域的应用前景广阔,并在多个领域中发挥着重要的作用。 ## Yarn @@ -21,4 +34,4 @@ 5. MapRedeuce ApplicationMaster 启动之后,立马向 Resource manager 注册,并为 MapReduce 申请资源。 6. MapReduce ApplicationMaster 申请到容器之后立马和 NodeManager 通信,将用户的 MapReduce 程序分发到对应的 Container 中运行,运行的是 Map 进行和 Reduce 进程。 7. Map 和 Reduce 进程执行期间与 MapReduce ApplicationMaster 进行通信,汇报自身的运行状态,如果运行结束,MapReduce ApplicationMaster ApplicationMaster 会向 ResourceManager 注销并释放所有的容器资源。 -8. 最后返回 Reduce 的所有结果。 \ No newline at end of file +8. 最后返回 Reduce 的所有结果。 diff --git a/bigdata/kafka_1.md b/bigdata/kafka_1.md index b867353..f67511b 100644 --- a/bigdata/kafka_1.md +++ b/bigdata/kafka_1.md @@ -12,7 +12,7 @@ kafka 的 message 是以 topic 为基本单位,不同 topic 之间是相互独 同一个 topic 的不同 partition 可以分布在不同的 broker 上,这正是分布式的设计。 partition 是以文件夹的形式存储在 broker 机器上。 topic 与 partition 的关系如下: - + ## Partition中的文件 ### segment file @@ -23,17 +23,17 @@ topic 与 partition 的关系如下: 2. 自0.10.0.1开始的kafka segment file组成:多了一部分,还有 .timeindex 索引文件,基于时间的索引文件;目前支持的时间戳类型有两种: CreateTime 和 LogAppendTime 前者表示 producer 创建这条消息的时间;后者表示 broker 接收到这条消息的时间(严格来说,是 leader broker 将这条消息写入到 log 的时间) 3. segment file 命名规则:partition 的第一个 segment 从0开始,后续每个 segment 文件名为上一个 segment 文件最后一条消息的 offset, ofsset 的数值最大为64位(long 类型),20位数字字符长度,没有数字用0填充。如下图所示: 老版本 segment file 结构: - + 新版本 segment file 结构: - + 4. 关于 segment file 中 index 索引文件与 data 文件对应关系图,这里我们借用网上的一个图片,如下所示: - + 5. segment的索引文件中存储着大量的元数据,数据文件中存储着大量消息,索引文件中的元数据指向对应数据文件中的 message 的物理偏移地址。以索引文件中的6,1407为例,在数据文件中表示第6个 message(在全局 partition 表示第368775个 message),以及该消息的物理偏移地址为1407。 6. Kafka message 结构如下图: - + `注`:.index文件的第一个数是 message 相对 offset,后面的数字是该消息的物理偏移地址。 diff --git a/bigdata/src/main/java/cn/tommyyang/bigfile/BigFile.java b/bigdata/src/main/java/cn/tommyyang/bigfile/BigFile.java index 34f3ae8..abc8c96 100644 --- a/bigdata/src/main/java/cn/tommyyang/bigfile/BigFile.java +++ b/bigdata/src/main/java/cn/tommyyang/bigfile/BigFile.java @@ -6,16 +6,17 @@ /** * @author TommyYang on 2019年04月09日 + * + * 使用说明 + * run cmd: java -cp bigdata-1.0-SNAPSHOT.jar cn.tommyyang.bigfile.BigFile */ - -//run cmd: java -cp bigdata-1.0-SNAPSHOT.jar cn.tommyyang.bigfile.BigFile public class BigFile { public static void main(String[] args) throws IOException { //BigFileTool.readContent(args[0], args[1]); FileService fileService = new FileService("./smallfiles/sink-0.txt"); fileService.countWords(); - //System.out.println(fileService.getTreeMap()); + System.out.println(fileService.getTreeMap()); System.out.println(fileService.getTreeMap().firstEntry().getKey() + ":" + fileService.getTreeMap().firstEntry().getValue()); } diff --git a/books/README.md b/books/README.md index dd27b6a..3c2a045 100644 --- a/books/README.md +++ b/books/README.md @@ -18,8 +18,18 @@ | Java8 实战.pdf | [下载](https://pan.baidu.com/s/1y5m1hgn9cJT7pyE5qI9UuQ) | og1w | | 深入理解 Java 虚拟机第二版.pdf | [下载](https://pan.baidu.com/s/1mFE-B03b5Dwuz3_CJgHA7g) | c1j1 | +## 算法 +| 书名 | 链接 | 提取码 | +| :----: | :----: | :----: | +| 编程珠玑(第 2 版).pdf | [下载](https://pan.baidu.com/s/174v9WNIHBFpAxmy9uCYX-g) | 5698 | + ## 架构 | 书名 | 链接 | 提取码 | | :----: | :----: | :----: | | 微服务设计.pdf | [下载](https://pan.baidu.com/s/1uaCQhagPU1ElrC2zuBePdA) | bfir | -| 大型网站技术架构.pdf | [下载](https://pan.baidu.com/s/1F_CpOz-0sspDjGktG1z3Yw) | wf1l | \ No newline at end of file +| 大型网站技术架构.pdf | [下载](https://pan.baidu.com/s/1F_CpOz-0sspDjGktG1z3Yw) | wf1l | + +## 人工智能 +### 读书笔记 +#### A/B测试 +![A/B测试](https://github.com/joyang1/JavaInterview/blob/master/img/AB%E6%B5%8B%E8%AF%95.png) \ No newline at end of file diff --git a/codeinterview/src/main/java/cn/tommyyang/listnode/ListNode.java b/codeinterview/src/main/java/cn/tommyyang/listnode/ListNode.java index dc2a9cc..55c7de4 100644 --- a/codeinterview/src/main/java/cn/tommyyang/listnode/ListNode.java +++ b/codeinterview/src/main/java/cn/tommyyang/listnode/ListNode.java @@ -13,6 +13,11 @@ public ListNode(int val) { this.val = val; } + public ListNode(int val, ListNode next) { + this.val = val; + this.next = next; + } + public ListNode getNext() { return next; } diff --git a/codeinterview/src/main/java/cn/tommyyang/listnode/ReverseLinkedList.java b/codeinterview/src/main/java/cn/tommyyang/listnode/ReverseLinkedList.java index bd85c99..745cd4d 100644 --- a/codeinterview/src/main/java/cn/tommyyang/listnode/ReverseLinkedList.java +++ b/codeinterview/src/main/java/cn/tommyyang/listnode/ReverseLinkedList.java @@ -1,6 +1,10 @@ package cn.tommyyang.listnode; /** + * 链表反转 + * 1、迭代算法 + * 2、递归算法 + * * @Author : TommyYang * @Time : 2019年06月19日 18:29 * @Software: IntelliJ IDEA @@ -8,21 +12,74 @@ */ public class ReverseLinkedList { - public ListNode reverse (ListNode head) { - + /** + * 迭代算法反转 + * + * @param head + * @return + */ + public ListNode reverseWithIterate(ListNode head) { ListNode cur = head; ListNode next; - ListNode left = null; + ListNode pre = null; while (cur != null) { next = cur.next; - cur.next = left; - left = cur; + cur.next = pre; + pre = cur; cur = next; } + return pre; + } + + /** + * 递归算法反转 + * + * @param head + * @return + */ + public ListNode reverseWithRecursion(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode newNode = reverseWithRecursion(head.next); + + head.next.next = head; + head.next = null; + + return newNode; + } + + public static void main(String[] args) { + ListNode node5 = new ListNode(5, null); + ListNode node4 = new ListNode(4, node5); + ListNode node3 = new ListNode(3, node4); + ListNode node2 = new ListNode(2, node3); + ListNode node1 = new ListNode(1, node2); - return left; + print(node1); + ListNode newNode = new ReverseLinkedList().reverseWithRecursion(node1); + + print(newNode); } + /** + * 打印链表 + * + * @param head 链表头 + */ + private static void print(ListNode head) { + while (head != null) { + System.out.print(head.val); + if (head.next != null) { + System.out.print("->"); + } + head = head.next; + } + System.out.println(); + } + + } diff --git a/datastructure/README.md b/datastructure/README.md deleted file mode 100644 index f08867b..0000000 --- a/datastructure/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# 数据结构篇 - -## [String、StringBuilder和StringBuffer](stringbuilderandstringbuffer.md) -| 类名| 描述| 是否可| 线程安全性| -|:---- |:---- |:---- |:---- | -|String |字符串常量 | 不可变类 | 线程安全 | -|StringBuilder |字符串变量 | 可变类 | 线程不安全 | -|StringBuffer |字符串变量 | 可变类 | 线程安全 | - -## [BlockingQueue](blockingqueueanddeque.md) - -## [线程池相关](threadpool.md) - -## SimpleDateFormat \ No newline at end of file diff --git "a/img/AB346円265円213円350円257円225円.png" "b/img/AB346円265円213円350円257円225円.png" new file mode 100644 index 0000000..5071b60 Binary files /dev/null and "b/img/AB346円265円213円350円257円225円.png" differ diff --git "a/img/tommy345円255円246円344円271円240円345円275円225円.png" "b/img/tommy345円255円246円344円271円240円345円275円225円.png" new file mode 100644 index 0000000..133cc3d Binary files /dev/null and "b/img/tommy345円255円246円344円271円240円345円275円225円.png" differ diff --git a/javabase/README.md b/javabase/README.md new file mode 100644 index 0000000..16994e2 --- /dev/null +++ b/javabase/README.md @@ -0,0 +1,103 @@ +# Java 基础知识 + +## 基础 +### Integer类 +```java + +public class Test { + public static void main(String[] args){ + Integer a = new Integer(129); + Integer b = new Integer(129); + + // 1 + System.out.println(a == b); + + + Integer c = new Integer(127); + Integer d = new Integer(127); + // 2 + System.out.println(c == d); + } +} + +``` + +上述代码可以看出1处 输出 false; 2 处输出 true。 +从Integer类源码中,有一个内部类,代码如下: +```java + +private static class IntegerCache { + static final int low = -128; + static final int high; + static final Integer cache[]; + + static { + // high value may be configured by property + int h = 127; + String integerCacheHighPropValue = + sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); + if (integerCacheHighPropValue != null) { + try { + int i = parseInt(integerCacheHighPropValue); + i = Math.max(i, 127); + // Maximum array size is Integer.MAX_VALUE + h = Math.min(i, Integer.MAX_VALUE - (-low) -1); + } catch( NumberFormatException nfe) { + // If the property cannot be parsed into an int, ignore it. + } + } + high = h; + + cache = new Integer[(high - low) + 1]; + int j = low; + for(int k = 0; k < cache.length; k++) + cache[k] = new Integer(j++); + + // range [-128, 127] must be interned (JLS7 5.1.7) + assert IntegerCache.high>= 127; + } + + private IntegerCache() {} + } + +``` +从上述源码可以找出出现上述1处、2处结果的原因。 + + +### Calendar类 +> 添加天数:DAY_OF_MONTH、DAY_OF_YEAR、DAY_OF_WEEK、DAY_OF_WEEK_IN_MONTH的区别 + +就单纯的add操作结果都一样,因为都是将日期+1, 不管是月的日期中加1还是年的日期中加1。
+强行解释区别如下:
+- `DAY_OF_MONTH` 的主要作用是get(DAY_OF_MONTH),用来获得这一天在是这个月的第多少天。 +- `DAY_OF_YEAR` 的主要作用get(DAY_OF_YEAR),用来获得这一天在是这个年的第多少天。 +- 同样,`DAY_OF_WEEK`,用来获得当前日期是一周的第几天;`DAY_OF_WEEK_IN_MONTH`,用来获取 day 所在的周是这个月的第几周 + +### [String、StringBuilder和StringBuffer](stringbuilderandstringbuffer.md) +| 类名| 描述| 是否可| 线程安全性| +|:---- |:---- |:---- |:---- | +|String |字符串常量 | 不可变类 | 线程安全 | +|StringBuilder |字符串变量 | 可变类 | 线程不安全 | +|StringBuffer |字符串变量 | 可变类 | 线程安全 | + +### [关键字篇](keywords) +- [transient](keywords/transient.md) +- [volatile](keywords/volatile.md) + + +## [异常篇](exception.md) + +## [Java8 篇](java8) + +## :house_with_garden: [数据结构篇](datastructure) +- [BlockingQueue和BlockingDeque](datastructure/blockingqueueanddeque.md) + * Queue + * Deque + * LinkedList + * ArrayBlockingQueue + * LinkedBlockingQueue + * LinkedBlockingDeque + +## 多线程相关 +- [线程池](threadpool.md) + diff --git a/javabase/datastructure/README.md b/javabase/datastructure/README.md new file mode 100644 index 0000000..41f3057 --- /dev/null +++ b/javabase/datastructure/README.md @@ -0,0 +1,5 @@ +# 数据结构篇 + +## [BlockingQueue](blockingqueueanddeque.md) + +## [线程池相关](../threadpool.md) \ No newline at end of file diff --git a/datastructure/blockingqueueanddeque.md b/javabase/datastructure/blockingqueueanddeque.md similarity index 100% rename from datastructure/blockingqueueanddeque.md rename to javabase/datastructure/blockingqueueanddeque.md diff --git a/datastructure/pom.xml b/javabase/datastructure/pom.xml similarity index 90% rename from datastructure/pom.xml rename to javabase/datastructure/pom.xml index b9a6a53..09511d5 100644 --- a/datastructure/pom.xml +++ b/javabase/datastructure/pom.xml @@ -16,8 +16,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 1.17 + 1.17 diff --git a/datastructure/src/main/java/cn/tommyyang/RunTest.java b/javabase/datastructure/src/main/java/cn/tommyyang/RunTest.java similarity index 100% rename from datastructure/src/main/java/cn/tommyyang/RunTest.java rename to javabase/datastructure/src/main/java/cn/tommyyang/RunTest.java diff --git a/datastructure/src/main/java/cn/tommyyang/forkjoinpool/CountTask.java b/javabase/datastructure/src/main/java/cn/tommyyang/forkjoinpool/CountTask.java similarity index 100% rename from datastructure/src/main/java/cn/tommyyang/forkjoinpool/CountTask.java rename to javabase/datastructure/src/main/java/cn/tommyyang/forkjoinpool/CountTask.java diff --git a/datastructure/src/main/java/cn/tommyyang/queue/ArrayBlockingQueueDemo.java b/javabase/datastructure/src/main/java/cn/tommyyang/queue/ArrayBlockingQueueDemo.java similarity index 100% rename from datastructure/src/main/java/cn/tommyyang/queue/ArrayBlockingQueueDemo.java rename to javabase/datastructure/src/main/java/cn/tommyyang/queue/ArrayBlockingQueueDemo.java diff --git a/datastructure/src/main/java/cn/tommyyang/string/StringTest.java b/javabase/datastructure/src/main/java/cn/tommyyang/string/StringTest.java similarity index 100% rename from datastructure/src/main/java/cn/tommyyang/string/StringTest.java rename to javabase/datastructure/src/main/java/cn/tommyyang/string/StringTest.java diff --git a/javabase/exception.md b/javabase/exception.md new file mode 100644 index 0000000..47cbae6 --- /dev/null +++ b/javabase/exception.md @@ -0,0 +1,157 @@ +# 异常介绍 +异常就是有异于常态,和正常情况不一样,有错误出现。在java中,阻止当前方法或作用域的情况,称之为异常。 + +## 异常分类 +![异常分类图](https://cdn.jsdelivr.net/gh/filess/img6@main/2021/03/27/1616860311636-a2466f2e-6bb2-437e-bd71-b2124af3fd89.png) + +## Exception具体实现 +在系统开发中,平时经常需要使用的两种异常,一种是需要检查(checked)的,一种是不需要检查(unchecked)的。 +那为什么需要两种异常呢? +- 用来区分告警的优先级。系统异常优先级高,因为说明系统服务、代码存在问题。 + - 业务异常,是已知的,因为其他客观因素导致的,比如用户输入的身份证格式有问题、用户购买商品时金额不足等。 + - 系统异常,是未知的,不知道啥时候会发生,如果发生了说明系统本身或者系统上下游存在问题,需要立马告警出来,让相关开发者感知到;以便发现问题和后续优化问题。比如:系统上下游服务抖动、请求超时、请求参数存在问题等。 +- 使代码更清洁,该处理(checked)的异常内部处理掉,无法处理(unchecked)的异常告警出来。 + +往往对于开发者来说,比较难区分,何为系统系统,何为业务异常。其中系统异常是unchecked的,业务异常是checked。 + +### RuntimeException +`RuntimeException`是在Java虚拟机的正常操作期间可以抛出的那些异常的超类,是Exception的子类,是Exception中unchecked子类的超类。 +比如系统上下游抖动、请求超时等,是允许在系统运行期间抛出的,所以该类异常应该继承自`RuntimeException`;且无需检查(unchecked)。 +所以系统异常应该继承自`RuntimeException`。 + +开发时具体实现: + +```java + +/** + * @Author : TommyYang + * @Time : 2021年03月27日 12:40 + * @Software: IntelliJ IDEA + * @File : SystemException.java + */ +public class SystemException extends RuntimeException { + + private String code; + + public SystemException(String code) { + this.code = code; + } + + public SystemException(String message, String code) { + super(message); + this.code = code; + } + + @Override + public String toString() { + return "SystemException{" + + "code='" + code + '\'' + + '}'; + } + +} + +``` + +### Exception +异常类和任何不是RuntimeException的子类的子类都是检查异常。 检查的异常需要在方法或构造函数的throws子句中声明,如果它们可以通过执行方法或构造函数抛出,并在方法或构造函数边界之外传播。 +比如用户输入的身份证格式有问题、用户购买商品时金额不足等,这些是在开发系统的时候,就会已经的会出现这样的问题,这类异常是应该内部处理(checked)掉,而不应该告警出来。 +所以业务异常应该继承自`Exception`,且需要检查(checked)。 + +开发时具体实现: + +```java + +/** + * @Author : TommyYang + * @Time : 2021年03月27日 12:40 + * @Software: IntelliJ IDEA + * @File : BusinessException.java + */ +public class BusinessException extends Exception { + + private String code; + + public BusinessException(String code) { + this.code = code; + } + + public BusinessException(String message, String code) { + super(message); + this.code = code; + } + + @Override + public String toString() { + return "BusinessException{" + + "code='" + code + '\'' + + '}'; + } +} + +``` + +### 测试 + +```java + +/** + * @Author : TommyYang + * @Time : 2021年03月27日 13:19 + * @Software: IntelliJ IDEA + * @File : ExceptionTest.java + */ +public class ExceptionTest { + + /** + * 测试checked异常 + */ + @Test + public void testException() { + try { + throwsBusinessException(); + } catch (BusinessException e) { + System.out.println("这是一个业务异常,内部处理掉" + e.toString()); + } + } + + /** + * 测试unchecked异常 + */ + @Test + public void testRuntimeException() { + throwsSystemException(); + } + + /** + * 抛出业务异常(checked) + * 所以需要throw出去,让外部调用方感知到,这是一个checked的异常,是已经问题 + */ + private void throwsBusinessException() throws BusinessException { + throw new BusinessException("403"); + } + + /** + * 抛出系统异常(unchecked) + */ + private void throwsSystemException() { + throw new SystemException("400"); + } + +} + +``` + +## Error介绍 +`Error`表示严重的问题,合理的应用程序不应该试图捕获。 大多数这样的错误是异常情况。 ThreadDeath错误虽然是"正常"的条件,但也是Error一个子类,因为大多数应用程序不应该试图抓住它。 + +`Error`是由虚拟机生成并抛出,大多数错误与代码开发者所执行的操作无关。 +常见的Error,比如Java虚拟机运行错误(VirtualMachineError);当JVM执行操作所需的内存资源不够时,将出现OutOfMemoryError;当这些异常发生时,JVM一般会选择线程终止。 +还有部分Error是发生在虚拟机试图执行应用时,比如类定义错误(NoClassDefFoundError)、链接错误(LinkageError);这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。 +对于合理设计的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。 +在Java中,错误通常是使用Error的子类描述。 + + + + + diff --git a/javabase/img/exception_category.png b/javabase/img/exception_category.png new file mode 100644 index 0000000..e04bca1 Binary files /dev/null and b/javabase/img/exception_category.png differ diff --git a/java8/README.md b/javabase/java8/README.md similarity index 100% rename from java8/README.md rename to javabase/java8/README.md diff --git a/java8/pom.xml b/javabase/java8/pom.xml similarity index 95% rename from java8/pom.xml rename to javabase/java8/pom.xml index 894ed41..b0be4ac 100644 --- a/java8/pom.xml +++ b/javabase/java8/pom.xml @@ -9,7 +9,7 @@ 4.0.0 - java8 + javabase diff --git a/java8/src/main/java/cn/tommyyang/functioninterface/ApplePredicate.java b/javabase/java8/src/main/java/cn/tommyyang/functioninterface/ApplePredicate.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/functioninterface/ApplePredicate.java rename to javabase/java8/src/main/java/cn/tommyyang/functioninterface/ApplePredicate.java diff --git a/java8/src/main/java/cn/tommyyang/functioninterface/DefaultInterface.java b/javabase/java8/src/main/java/cn/tommyyang/functioninterface/DefaultInterface.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/functioninterface/DefaultInterface.java rename to javabase/java8/src/main/java/cn/tommyyang/functioninterface/DefaultInterface.java diff --git a/java8/src/main/java/cn/tommyyang/functioninterface/Demo.java b/javabase/java8/src/main/java/cn/tommyyang/functioninterface/Demo.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/functioninterface/Demo.java rename to javabase/java8/src/main/java/cn/tommyyang/functioninterface/Demo.java diff --git a/java8/src/main/java/cn/tommyyang/functioninterface/Predicate.java b/javabase/java8/src/main/java/cn/tommyyang/functioninterface/Predicate.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/functioninterface/Predicate.java rename to javabase/java8/src/main/java/cn/tommyyang/functioninterface/Predicate.java diff --git a/java8/src/main/java/cn/tommyyang/functioninterface/ProgressDemo.java b/javabase/java8/src/main/java/cn/tommyyang/functioninterface/ProgressDemo.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/functioninterface/ProgressDemo.java rename to javabase/java8/src/main/java/cn/tommyyang/functioninterface/ProgressDemo.java diff --git a/java8/src/main/java/cn/tommyyang/model/Apple.java b/javabase/java8/src/main/java/cn/tommyyang/model/Apple.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/model/Apple.java rename to javabase/java8/src/main/java/cn/tommyyang/model/Apple.java diff --git a/java8/src/main/java/cn/tommyyang/model/Fruit.java b/javabase/java8/src/main/java/cn/tommyyang/model/Fruit.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/model/Fruit.java rename to javabase/java8/src/main/java/cn/tommyyang/model/Fruit.java diff --git a/java8/src/main/java/cn/tommyyang/model/Pear.java b/javabase/java8/src/main/java/cn/tommyyang/model/Pear.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/model/Pear.java rename to javabase/java8/src/main/java/cn/tommyyang/model/Pear.java diff --git a/java8/src/main/java/cn/tommyyang/streamapi/CountService.java b/javabase/java8/src/main/java/cn/tommyyang/streamapi/CountService.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/streamapi/CountService.java rename to javabase/java8/src/main/java/cn/tommyyang/streamapi/CountService.java diff --git a/java8/src/main/java/cn/tommyyang/streamapi/StreamAPI.java b/javabase/java8/src/main/java/cn/tommyyang/streamapi/StreamAPI.java similarity index 100% rename from java8/src/main/java/cn/tommyyang/streamapi/StreamAPI.java rename to javabase/java8/src/main/java/cn/tommyyang/streamapi/StreamAPI.java diff --git a/keywords/README.md b/javabase/keywords/README.md similarity index 100% rename from keywords/README.md rename to javabase/keywords/README.md diff --git a/keywords/pom.xml b/javabase/keywords/pom.xml similarity index 100% rename from keywords/pom.xml rename to javabase/keywords/pom.xml diff --git a/keywords/res/transient.png b/javabase/keywords/res/transient.png similarity index 100% rename from keywords/res/transient.png rename to javabase/keywords/res/transient.png diff --git a/keywords/res/transienttest.txt b/javabase/keywords/res/transienttest.txt similarity index 100% rename from keywords/res/transienttest.txt rename to javabase/keywords/res/transienttest.txt diff --git a/keywords/src/main/java/transientkey/TransientTest.java b/javabase/keywords/src/main/java/transientkey/TransientTest.java similarity index 100% rename from keywords/src/main/java/transientkey/TransientTest.java rename to javabase/keywords/src/main/java/transientkey/TransientTest.java diff --git a/keywords/src/main/java/volatilekey/ordering/AThread.java b/javabase/keywords/src/main/java/volatilekey/ordering/AThread.java similarity index 100% rename from keywords/src/main/java/volatilekey/ordering/AThread.java rename to javabase/keywords/src/main/java/volatilekey/ordering/AThread.java diff --git a/keywords/src/main/java/volatilekey/ordering/BThread.java b/javabase/keywords/src/main/java/volatilekey/ordering/BThread.java similarity index 100% rename from keywords/src/main/java/volatilekey/ordering/BThread.java rename to javabase/keywords/src/main/java/volatilekey/ordering/BThread.java diff --git a/keywords/src/main/java/volatilekey/ordering/Model.java b/javabase/keywords/src/main/java/volatilekey/ordering/Model.java similarity index 100% rename from keywords/src/main/java/volatilekey/ordering/Model.java rename to javabase/keywords/src/main/java/volatilekey/ordering/Model.java diff --git a/keywords/src/main/java/volatilekey/ordering/RunTest.java b/javabase/keywords/src/main/java/volatilekey/ordering/RunTest.java similarity index 100% rename from keywords/src/main/java/volatilekey/ordering/RunTest.java rename to javabase/keywords/src/main/java/volatilekey/ordering/RunTest.java diff --git a/keywords/src/main/java/volatilekey/unsafe/Counter.java b/javabase/keywords/src/main/java/volatilekey/unsafe/Counter.java similarity index 100% rename from keywords/src/main/java/volatilekey/unsafe/Counter.java rename to javabase/keywords/src/main/java/volatilekey/unsafe/Counter.java diff --git a/keywords/src/main/java/volatilekey/unsafe/OwnUnSafe.java b/javabase/keywords/src/main/java/volatilekey/unsafe/OwnUnSafe.java similarity index 100% rename from keywords/src/main/java/volatilekey/unsafe/OwnUnSafe.java rename to javabase/keywords/src/main/java/volatilekey/unsafe/OwnUnSafe.java diff --git a/keywords/src/main/java/volatilekey/unsafe/Runtest.java b/javabase/keywords/src/main/java/volatilekey/unsafe/Runtest.java similarity index 100% rename from keywords/src/main/java/volatilekey/unsafe/Runtest.java rename to javabase/keywords/src/main/java/volatilekey/unsafe/Runtest.java diff --git a/keywords/src/main/java/volatilekey/unsafe/ThreadCommunicate.java b/javabase/keywords/src/main/java/volatilekey/unsafe/ThreadCommunicate.java similarity index 100% rename from keywords/src/main/java/volatilekey/unsafe/ThreadCommunicate.java rename to javabase/keywords/src/main/java/volatilekey/unsafe/ThreadCommunicate.java diff --git a/keywords/src/main/java/volatilekey/visibility/RunTest.java b/javabase/keywords/src/main/java/volatilekey/visibility/RunTest.java similarity index 100% rename from keywords/src/main/java/volatilekey/visibility/RunTest.java rename to javabase/keywords/src/main/java/volatilekey/visibility/RunTest.java diff --git a/keywords/transient.md b/javabase/keywords/transient.md similarity index 100% rename from keywords/transient.md rename to javabase/keywords/transient.md diff --git a/keywords/volatile.md b/javabase/keywords/volatile.md similarity index 100% rename from keywords/volatile.md rename to javabase/keywords/volatile.md diff --git a/datastructure/stringbuilderandstringbuffer.md b/javabase/stringbuilderandstringbuffer.md similarity index 100% rename from datastructure/stringbuilderandstringbuffer.md rename to javabase/stringbuilderandstringbuffer.md diff --git a/datastructure/threadpool.md b/javabase/threadpool.md similarity index 100% rename from datastructure/threadpool.md rename to javabase/threadpool.md diff --git a/jvm/garbage_collectors.md b/jvm/garbage_collectors.md index a105090..313552a 100644 --- a/jvm/garbage_collectors.md +++ b/jvm/garbage_collectors.md @@ -13,7 +13,7 @@ - G1 收集器 按收集器的回收对象以及收集器之间的联系,可以参照下图一: - + 通过上图可以发现,Serial、ParNew、 Parallel Scavenge 是用来收集新生代的收集器,CMS、 Serial Old、Parallel Old 是用来收集老年代的收集器;然后 CMS 是不能和 Parallel Scavenge 结合起来用的,CMS 是可以和 Serial Old 联合起来收集老年代的。 @@ -22,7 +22,7 @@ Serial 收集器是最基本、发展历史最悠久的收集器,(在JDK 1.3.1 之前)是虚拟机新生代收集的唯一选择。通过名字,大家也可以发现该收集器是一个单线程的收集器,但它的"单线程"的意义并不仅仅说明它只会使用一个 CPU 或 一条收集线程去完成垃圾收集工作,更重要的是在它进行收集时,必须暂停其它所有的工作线程,直到它收集结束。"Stop The World"就是该收集器的一个特点,这项工作是由虚拟机在后台自动发起和自动完成的,在用户不可见的情况下把用户正常工作的线程全部停掉,这对很多应用来说都是难以接受的。 Serial 收集器的工作过程如下图二: - + 对于 "Stop The World" 带给用户的不良体验,虚拟机的设计者们表示完全理解,但是表示非常委屈:"你妈妈在给你打扫房间的时候,肯定也会让你处在一个不会干扰她打扫的状态,比如坐在椅子上不动,或者到房间外面去,不然她一边打扫,你一边乱扔垃圾,这房间还能打扫完?"这确实是一个合情合理的矛盾,虽然垃圾收集这项工作听起来和打扫房间属于一个性质的,但实际上肯定还要比打扫房间复杂很多很多的。 @@ -34,7 +34,7 @@ Serial 收集器是虚拟机运行在 Client 模式下的默认新生代收集 ParNew 收集器其实就是 Serial 收集器的多线程版本。其它的与 Serial 收集器基本相同,也是 Stop The World,在实现上,这两种收集器也共用了相当多的代码。 ParNew 收集器的工作过程如下图三: - + ParNew 收集器是许多运行在 Server 模式下的虚拟机中首选的新生代收集器,其中有一个与性能无关但很重要的原因,除了 Serial 收集器外,目前只有它能与 CMS 收集器配合工作。 CMS 收集器是在 JDK 1.5时期推出的一款真正意义上的并发(Concurrent)收集器,它第一次实现了让垃圾收集器与用户线程(基本上)同时工作,用前面的例子来说就是做到了在你妈妈打扫房间的同时你还能一边往地上扔垃圾。 diff --git a/keywords/src/main/java/transientkey/RunTest.java b/keywords/src/main/java/transientkey/RunTest.java deleted file mode 100644 index daa8e1e..0000000 --- a/keywords/src/main/java/transientkey/RunTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package transientkey; - -import java.io.*; - -/** - * Created by TommyYang on 2018年3月19日. - */ -public class RunTest { - - public static void main(String[] args) throws IOException, ClassNotFoundException { - //write Serializable object to file - TransientTest test = new TransientTest(); - FileOutputStream fileOutputStream = new FileOutputStream("KeyWords/res/transienttest.txt"); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); - objectOutputStream.writeObject(test); - objectOutputStream.flush(); - objectOutputStream.close(); - - //get Serializable object from file - ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("KeyWords/res/transienttest.txt")); - TransientTest transientTest = (TransientTest) objectInputStream.readObject(); - System.out.println("a=" + transientTest.getA() + "\t" +"b=" + transientTest.getB()); - } - -} diff --git a/lock/src/main/java/cn/tommyyang/distributedlock/RedisDistributedLock.java b/lock/src/main/java/cn/tommyyang/distributedlock/RedisDistributedLock.java new file mode 100644 index 0000000..c5c4fd1 --- /dev/null +++ b/lock/src/main/java/cn/tommyyang/distributedlock/RedisDistributedLock.java @@ -0,0 +1,10 @@ +package cn.tommyyang.distributedlock; + +/** + * @author TommyYang on 2019年05月12日 + */ +public class RedisDistributedLock { + + + +} diff --git a/machinelearning/model.md b/machinelearning/model.md new file mode 100644 index 0000000..6ed8ec6 --- /dev/null +++ b/machinelearning/model.md @@ -0,0 +1,391 @@ +# 相关模型介绍 +# 分类模型 + +## 决策树 +决策树(Decision Tree)算法是一种基本的分类与回归方法,是最经常使用的数据挖掘算法之一。我们这章节只讨论用于分类的决策树。 + +决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是 if-then 规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。 + +决策树学习通常包括 3 个步骤: 特征选择、决策树的生成和决策树的修剪。 + +### 决策树场景 +一个叫做 "二十个问题" 的游戏,游戏的规则很简单: 参与游戏的一方在脑海中想某个事物,其他参与者向他提问,只允许提 20 个问题,问题的答案也只能用对或错回答。问问题的人通过推断分解,逐步缩小待猜测事物的范围,最后得到游戏的答案。 + +**一个邮件分类系统,大致工作流程如下**: +![邮件分类](https://blog.tommyyang.cn/img/ml/model/dt_email.png) + +- 首先检测发送邮件域名地址。如果地址为 myEmployer.com, 则将其放在分类 "无聊时需要阅读的邮件"中。 +- 如果邮件不是来自这个域名,则检测邮件内容里是否包含单词 "曲棍球" , 如果包含则将邮件归类到 "需要及时处理的朋友邮件"。 +- 如果不包含则将邮件归类到 "无需阅读的垃圾邮件" 。 + +**假如你了解足球,让你预测世界杯 32 个球队哪支球队是冠军**: +![预测夺冠](https://blog.tommyyang.cn/img/ml/model/dt_32_champion.png) + +- 在 1-16 么?在 +- 在 9-16 么?在 +- 在 13-16 么? 在 +- 在 15 -16 么? 在 +- 是 15 么? 不是 + +答案:16 号球队夺冠。 + +`tips` +最多通过 5 次机会就猜测出哪只球队是冠军球队。这个 5 代表的是 5 bit(比特),相当于是 2^5=32,通过 5 bit 可以描述出这个信息量。 +如果是 64 支球队,那么需要 6 bit 来描述这个信息量。 + +### 信息熵(香农熵) +香农通过世界杯预测冠军的问题提出了信息熵,故信息熵也叫香农熵,信息熵用来度量信息量;信息量的度量等于不确定性的多少。 +通过上述问题描述,相信读者已经了解了信息量的比特数和所有可能情况的对数函数 log 有关。(log32 = 5, log64 = 6)。 + +当然,如果是你对足球比较了解,通过历届球队的实力比较了解,以及世界杯参赛球队球星也比较了解。你可能会对一些球队能力的强弱进行分组, +因为你了解的信息量会多一些,所以猜测的不确定性就会小一些,从而你可能不需要 5 次就可以猜中。故香农提出了如下公式来计算信息熵: +H(x) = -(P1 * logP1 + P2 * logP2 + P3 * logP3 + ... + P32 * logP32), +其中P1、P2、P3...P32 分别代表 32 支球队夺冠的概率。 + +### 信息增益 +信息增益 = 信息熵 - 条件熵。 + +条件熵:在你得知一个信息(条件)后,得出结论还需要多少信息量。 + +信息增益越大,说明你得到的这个信息就越重要。 + +### 决策树定义 +分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node)和有向边(directed edge)组成。结点有两种类型: 内部结点(internal node)和叶结点(leaf node)。内部结点表示一个特征或属性(features),叶结点表示一个类(labels)。 + +用决策树对需要测试的实例进行分类: 从根节点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到其子结点;这时,每一个子结点对应着该特征的一个取值。如此递归地对实例进行测试并分配,直至达到叶结点。最后将实例分配到叶结点的类中。 + +### 决策树工作原理 +如何构造一个决策树? + +使用 create_branch() 方法,伪代码如下所示: +``` + +def createBranch(): +''' +此处运用了迭代的思想。 感兴趣可以搜索 迭代 recursion, 甚至是 dynamic programing。 +''' + 检测数据集中的所有数据的分类标签是否相同: + If so return 类标签 + Else: + 寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征) + 划分数据集 + 创建分支节点 + for 每个划分的子集 + 调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中 + return 分支节点 + +``` + +### 决策树开发流程 +- 收集数据: 可以使用任何方法。 +- 准备数据: 树构造算法 (这里使用的是ID3算法,只适用于标称型数据,这就是为什么数值型数据必须离散化。 还有其他的树构造算法,比如CART)。 +- 分析数据: 可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期。 +- 训练算法: 构造树的数据结构。 +- 测试算法: 使用训练好的树计算错误率。 +- 使用算法: 此步骤可以适用于任何监督学习任务,而使用决策树可以更好地理解数据的内在含义。 + +### 决策树算法特点 +- 优点: 计算复杂度不高,输出结果易于理解,数据有缺失也能跑,可以处理不相关特征。 +- 缺点: 容易过拟合。 +- 适用数据类型: 数值型和标称型。 + +### 决策树案例分析 +#### 实例一 鱼类非鱼类问题 +决策树如下: +![预测夺冠](https://blog.tommyyang.cn/img/ml/model/dt_fish.png) + +##### 项目概述 +根据以下 2 个特征,将动物分成两类: 鱼类和非鱼类。 + +特征: +- 不浮出水面是否可以生存。 +- 是否有脚蹼(du 第三声)。 + +##### 构造数据集 +``` python +# 构造数据集 +def create_data_set(): + """ + :return: data_set 数据集, labels 标签数组 + """ + data_set = [ + [1, 1, 'yes'], + [1, 1, 'yes'], + [1, 0, 'no'], + [0, 1, 'no'], + [0, 1, 'no'], + [0, 0, 'no'] + ] + + labels = ['no surfacing', 'flippers'] + + return data_set, labels +``` + +##### 计算香农熵(经验熵)shannonEnt +```python + +# 计算香农熵(经验熵)shannonEnt +def calc_shannon_ent(data_set): + """ + + :param data_set: 数据集 + :return: shannon_ent 香农熵 + + """ + + # 计算 list 的长度,表示计算参与训练的数据量 + num_entries = len(data_set) + # 计算分类标签 label 出现的次数 + label_counts = {} + + for feat_vec in data_set: + # 存储当前实例的标签存储,即每一行数据的最后一个数据代表的是标签 + current_label = feat_vec[-1] + # 为所有可能的分类创建字典,如果当前值不存在,则扩展字典并将当前值加入字典。每个键值都记录了当前类别出现的次数。 + if current_label not in label_counts.keys(): + label_counts[current_label] = 0 + label_counts[current_label] += 1 + + # 对于 label 标签的占比,求出 label 标签的香农熵 + shannon_ent = 0.0 + for key in label_counts: + # 使用所有类标签的发生频率计算类别出现的概率 + prob = float(label_counts[key]) / num_entries + # 计算香农熵 + shannon_ent -= prob * log(prob, 2) + + return shannon_ent + +``` + +##### 将指定特征值等于 value 的行剩下列作为子数据集 +``` python +# 将指定特征值等于 value 的行剩下列作为子数据集 +def split_data_set(data_set, index, value): + """ + (通过遍历 data_set 数据集,求出 index 对应的 column 列的值为 value 的行) + 就是依据 index 列进行分类,如果index列的数据等于 value 的时候,就要将 index 划分到我们创建的新的数据集中 + + :param data_set: 数据集 待划分的数据集 + :param index: 每一行的 index 列 划分数据集的特征 + :param value: index 列对应的 value 值 需要返回的特征的值 + :return: + ret_data_set 指定特征值等于 value 的行剩下列(不包含值等于该 value 的列)作为子数据集 + """ + ret_data_set = [] + for feat_vec in data_set: + # index 列为 value 的数据集[该数据集需要排除 index 列] + # 判断 index 列的值是否为 value + if feat_vec[index] == value: + # chop out index used for splitting + # [:index]表示前 index 行,即若 index 为 2,就是取 feat_vec 的前 2 行 + reduced_feat_vec = feat_vec[:index] + ''' + 请百度查询一下: extend和append的区别 + music_media.append(object) 向列表中添加一个对象object + music_media.extend(sequence) 把一个序列seq的内容添加到列表中 (跟 += 在list运用类似, music_media += sequence) + 1、使用append的时候,是将object看作一个对象,整体打包添加到music_media对象中。 + 2、使用extend的时候,是将sequence看作一个序列,将这个序列和music_media序列合并,并放在其后面。 + music_media = [] + music_media.extend([1,2,3]) + print music_media + #结果: + #[1, 2, 3] + + music_media.append([4,5,6]) + print music_media + #结果: + #[1, 2, 3, [4, 5, 6]] + + music_media.extend([7,8,9]) + print music_media + #结果: + #[1, 2, 3, [4, 5, 6], 7, 8, 9] + ''' + # 取 index+1 行开始,后面的所有行数据 + reduced_feat_vec.extend(feat_vec[index + 1:]) + + # 收集结果值 index 列为 value 的行[该行需要排除 index 列] + ret_data_set.append(reduced_feat_vec) + return ret_data_set +``` + +##### 选择信息增益最大的特征列 +```python + +def choose_best_feature_to_split(data_set): + """ + :param data_set: 数据集 + :return: + best_feature 最优的特征列 + """ + # 求第一行有多少列的 Feature, 最后一列是 label 列 + num_features = len(data_set[0]) - 1 + # 数据集的原始信息熵 + base_entropy = calc_shannon_ent(data_set) + # 最优的信息增益值, 和最优的 feature 编号 + best_info_gain, best_feature = 0.0, -1 + + # iterate over all the features + for i in range(num_features): + # create a list of all the examples of this feature + # 获取对应的 feature 下的所有数据 + feat_list = [example[i] for example in data_set] + # get a set of unique values + # 获取剔重后的集合,使用set对list数据进行去重 + unique_vals = set(feat_list) + print("unique_vals:", unique_vals) + # 创建一个临时的信息熵 + new_entropy = 0.0 + # 遍历某一列的 value 集合,计算该列的信息熵 + # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到的熵求和。 + for val in unique_vals: + sub_data_set = split_data_set(data_set, i, val) + # 计算概率 + prob = len(sub_data_set) / float(len(data_set)) + print("prob:", prob) + # 计算信息熵 + new_entropy += prob * calc_shannon_ent(sub_data_set) + print("new_entropy:", new_entropy) + # gain[信息增益]: 划分数据集前后的信息变化, 获取信息熵最大的值 + # 信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。 + info_gain: float = base_entropy - new_entropy + print('info_gain=', info_gain, 'best_feature=', i, base_entropy, new_entropy) + if info_gain> best_info_gain: + best_info_gain = info_gain + best_feature = i + return best_feature + +``` + +##### 构建决策树 +``` python + +def create_tree(data_set, labels): + """ + :param data_set: 数据集 + :param labels: label 标签 + :return: 返回决策树 + """ + class_list = [example[-1] for example in data_set] + # 如果数据集的最后一列的第一个值出现的次数=整个集合的数量,也就说只有一个类别,就只直接返回结果就行 + # 第一个停止条件: 所有的类标签完全相同,则直接返回该类标签。 + # count() 函数是统计括号中的值在list中出现的次数 + if class_list.count(class_list[0]) == len(class_list): + return class_list[0] + # 如果数据集只有 1 列,那么最初出现 label 次数最多的一类,作为结果 + # 第二个停止条件: 使用完了所有特征,仍然不能将数据集划分成仅包含唯一类别的分组。 + if len(data_set[0]) == 1: + return majority_cnt(class_list) + # 选择最优的列,得到最优列对应的label含义 + best_feat = choose_best_feature_to_split(data_set) + # 获取label的名称 + best_feat_label = labels[best_feat] + # 初始化myTree + my_tree = {best_feat_label: {}} + # 注: labels列表是可变对象,在PYTHON函数中作为参数时传址引用,能够被全局修改 + # 所以这行代码导致函数外的同名变量被删除了元素,造成例句无法执行,提示'no surfacing' is not in list + del (labels[best_feat]) + # 取出最优列,然后它的branch做分类 + feat_vals = [example[best_feat] for example in data_set] + unique_vals = set(feat_vals) + for val in unique_vals: + # 求出剩余的标签label + sub_labels = labels[:] + # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数create_tree() + my_tree[best_feat_label][val] = create_tree(split_data_set(data_set, best_feat, val), sub_labels) + # print('myTree', val, my_tree) + return my_tree + +``` + +##### 通过输入的特征,预测分类 +``` python + +def classify(input_tree, feat_labels, test_vec): + """ + 给输入的节点,进行分类 + :param input_tree: 决策树模型 + :param feat_labels: feature标签对应的名称 + :param test_vec: 测试输入的数据 + :return: + class_label 分类的结果值,需要映射 label 才能知道名称 + """ + # 获取 tree 的根节点对于的 key 值 + first_str = list(input_tree.keys())[0] + # 通过key得到根节点对应的value + second_dict = input_tree[first_str] + # 判断根节点名称获取根节点在label中的先后顺序,这样就知道输入的testVec怎么开始对照树来做分类 + feat_index = feat_labels.index(first_str) + # 测试数据,找到根节点对应的label位置,也就知道从输入的数据的第几位来开始分类 + key = test_vec[feat_index] + feat_val = second_dict[key] + print('+++', first_str, 'xxx', second_dict, '---', key, '>>>', feat_val) + # 判断分枝是否结束: 判断 feat_val 是否是 dict 类型 + if isinstance(feat_val, dict): + class_label = classify(feat_val, feat_labels, test_vec) + else: + class_label = feat_val + return class_label + +``` + +##### 选择出现次数最多的一个结果 +``` python + +def majority_cnt(class_list): + """ + 选择出现次数最多的一个结果 + :param class_list: label 列的集合 + :return: best_feature 最优的特征列 + """ + # -----------majorityCnt的第一种方式 start------------------------------------ + class_count = {} + for vote in class_list: + if vote not in class_count.keys(): + class_count[vote] = 0 + class_count[vote] += 1 + # 倒叙排列classCount得到一个字典集合,然后取出第一个就是结果(yes/no),即出现次数最多的结果 + sorted_class_count = sorted(class_count.iteritems(), key=operator.itemgetter(1), reverse=True) + print('sortedClassCount:', sorted_class_count) + return sorted_class_count[0][0] + # -----------majorityCnt的第一种方式 end------------------------------------ + + # # -----------majorityCnt的第二种方式 start------------------------------------ + # major_label = Counter(classList).most_common(1)[0] + # return major_label + # # -----------majorityCnt的第二种方式 end------------------------------------ + +``` + + +## GBDT +GBDT: Gradient Boost Decision Tree。DT-Decision Tree决策树,GB是Gradient Boosting,是一种学习策略,GBDT的含义就是用Gradient Boosting的策略训练出来的DT模型。可以处理二分类问题。 + + +## LightGBM + + +## XGBoost +### 分类树与回归树 +XGBoost是以CART回归树作为基本分类器。 +分类树:分类树的样本输出都是以类别的形式,比如说判断用户会不会购买华为Mate40,判断西瓜是甜还是不甜。 + +回归树:回归树的样本输出是数值的形式,比如给某人发放房屋贷款的数额,给某人发放的红包金额。 + +### Boost介绍 +Boost可以用于回归和分类问题,它每一步会产生一个弱分类器 (如决策树),然后通过加权累加起来变成一个强分类器。比如每一步都会产生一个f(x),F(x)=sum(fi(x)),其实就是一堆分类器通过加权合并成一个强分类器。 + +### 提升树 +首先要明确一点,xgboost 是基于提升树的。 + +什么是提升树,简单说,就是一个模型表现不好,我继续按照原来模型表现不好的那部分训练第二个模型,依次类推。 + +来几个形象的比喻就是: + +做题的时候,第一个人做一遍得到一个分数,第二个人去做第一个人做错的题目,第三个人去做第二个人做错的题目,以此类推,不停的去拟合从而可以使整张试卷分数可以得到100分(极端情况)。 + +把这个比喻替换到模型来说,就是真实值为100,第一个模型预测为90,差10分,第二个模型以10为目标值去训练并预测,预测值为7,差三分,第三个模型以3为目标值去训练并预测,以此类推。 + +## Random Forests diff --git a/machinelearning/recommend_system.md b/machinelearning/recommend_system.md new file mode 100644 index 0000000..d0ebaba --- /dev/null +++ b/machinelearning/recommend_system.md @@ -0,0 +1,53 @@ +# 推荐系统整理 +该篇主要对推荐系统进行一些整理。 + +## 推荐系统涉及到的一些模块 +核心模块有用户、Item(包括文章、视频、商品、音乐、电影等)、用户实时画像、Item 特征等。 +核心服务有召回服务、推荐服务、排序服务等。 + +如下图: +![相关模块](https://blog.tommyyang.cn/img/architecture/recommend-module.png) + +比较重要就是要去了解 NLP(自然语言处理),基于 NLP 的特征分析。基于模型的排序服务,比如决策树、FM 模型、FFM 模型、双线性 FFM 模型、DNN、Wide&Deep 等。排序模型个人觉得讲的比较好的一篇文章,[推荐排序模型](https://www.infoq.cn/article/vKoKh_ZDXcWRh8fLSsRp)。 + +## 推荐模型时序图 +![时序图](https://blog.tommyyang.cn/img/architecture/recommend-time.png) + +- 1.2.3 和 1.2.4 应该是在一步同时异步执行的 +- 1.3 获取文章title、content、发布时间、作者等相关信息 +- 1.2.3 里面包括 label 画像召回、LDA(Topic) 画像召回、用户与作者亲密度召回(我理解为基于社交关系的召回,这一类文章加上推荐理由效果会更好) + +tips: 为什么 Doc2vec 画像单独弄成一个微服务,因为 vector 是一个 300 维的 float 类型的数组,计算量特别大;所以做成 T+1 模式,提前计算好,然后索引到文件中。(使用的是开源的 Annoy 进行文件索引)。 + +## 实时画像时序图 +![实时画像时序图](https://blog.tommyyang.cn/img/architecture/recommend-profile-time.png) + +- 流处理框架使用当下比较流行的 Flink。 +- Flink 支持批量和流处理两种模式。 +- 批量计算时只是对接数据源不一样,数据仓库大多数为 Hive。 + +## 数据分析 +通过之前做过的一些视频、文章推荐举例。 + +- 多策略召回。 +- Rank 模型训练特征由离线转为实时。 +- 特征精细化,比如由文章总体 CTR 变为每个策略下的 CTR;不同分类下文章的时效性不一样,所以 CTR 计算周期不一样,比如有的文章在一开始 CTR 特别高,但随着时间变化,慢慢降低,但是相比其它的一些文章,还是很高,这时候,就需要调整 CTR 计算周期。 +- 分析重要的特征加入到训练模型,比如对文章来说:CTR、CDR;统计用户在每个分类下的 CTR、CDR,可以更加具体的描述出用户对不同分类的喜欢程度。 + +## 名词介绍 +- CTR:Click-Through-Rate,点击通过率。 +- CDR:Completion-reaDing-Rate,阅读完成率。 + +## 文章推荐 +- [从 FFM 到 DeepFFM,推荐排序模型到底哪家强?](https://www.infoq.cn/article/vKoKh_ZDXcWRh8fLSsRp) +- [NLP](https://easyai.tech/ai-definition/nlp/) +- [LDA](https://www.hankcs.com/nlp/lda-java-introduction-and-implementation.html) + + + + + + + + + diff --git a/machinelearning/tensorflow.md b/machinelearning/tensorflow.md new file mode 100644 index 0000000..4b0e209 --- /dev/null +++ b/machinelearning/tensorflow.md @@ -0,0 +1,2 @@ +# tensorflow 入门 +## 环境搭建 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3f161f9..0742932 100644 --- a/pom.xml +++ b/pom.xml @@ -10,16 +10,16 @@ 1.0-SNAPSHOT sortpro - keywords web lock bigdata codeinterview io test - datastructure + javabase/datastructure architecture - java8 + javabase/java8 + javabase/keywords diff --git a/test/src/main/java/StringUitls.java b/test/src/main/java/StringUitls.java new file mode 100644 index 0000000..f4807b6 --- /dev/null +++ b/test/src/main/java/StringUitls.java @@ -0,0 +1,27 @@ +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.stream.Stream; + +/** + * @Author : TommyYang + * @Time : 2019年09月17日 16:23 + * @Software: IntelliJ IDEA + * @File : StringUitls.java + */ +public class StringUitls { + + public static void main(String[] args) throws IOException { + Stream lines = Files.lines(Paths.get("/Users/tommy/Documents/aa.txt"), Charset.defaultCharset()); + lines.forEach(line -> { +// System.out.println(line.trim()); + int start = line.trim().indexOf(">"); + int end = line.trim().lastIndexOf("<"); + String value = line.trim().substring(start + 1, end); + line = line.trim().replace("