## 寒冬

2019 年 10 月 25 日下午六点零几分，离下班还有不到一个小时，突然接到HR的“DING”：来一趟Wework一楼小会议室。

HR 说你也知道我们公司的情况，我们也不容易，其中一个 HR 也是今天最后一天。稍微寒暄了一下，接着就开始谈赔偿。

10 月 31 号发了八月份的基本工资： 4950。至于剩下的部分，没有任何消息。

974 total views,  1 views today

## 快速排序算法。

``````<?php

/**
* Quick Sort Implement 1
* @param array \$array
* @return array
*/
function quickSort(array \$array) {
if (count(\$array) <= 1) {
return \$array;
}

\$middle = \$array;
\$left = [];
\$right = [];

for (\$i = 1; \$i < count(\$array); \$i++) {
if (\$array[\$i] < \$middle) {
\$left[] = \$array[\$i];
} else {
\$right[] = \$array[\$i];
}
}

return array_merge(quickSort(\$left), [\$middle], quickSort(\$right));
}

/**
* Quick Sort Implement 2
* @param array \$array
* @param  int \$start
* @param  int \$end
*/
function quickSort2(array &\$array, int \$start, int \$end) {
if (\$start >= \$end) {
return;
}

\$i = \$start;
\$middle = \$array[\$start];

for (\$j = \$start + 1; \$j <= \$end; \$j++) {
if (\$array[\$j] < \$middle) {
\$i++;
exchange(\$array[\$i], \$array[\$j]);
}
}

exchange(\$array[\$i], \$array[\$start]);

quickSort2(\$array, \$start, \$i - 1);
quickSort2(\$array, \$i + 1, \$end);
}

function exchange(&\$a, &\$b) {
[\$a, \$b] = [\$b, \$a];
}

function printArray(\$array) {
foreach (\$array as \$value) {
echo \$value, " ";
}
echo "\n";
}

\$array = [6, 5, 3, 1, 8, 7, 2, 4];
printArray(quickSort(\$array));
quickSort2(\$array, 0, count(\$array) - 1);
printArray(\$array);``````

## 自动加载原理。

``https://zyf.im/2019/04/28/php-composer-basic/``

## 工作中遇到的最难的问题是什么？怎么解决的。

351 total views,  1 views today

## 现在使用的 PHP 版本，有哪些新特性。

``````PHP 7.2

https://tanghengzhi.com/whats-new-in-php-72/``````

## 聊一聊PHP SPL，迭代器和生成器。

``````/**
* https://www.php.net/manual/en/intro.spl.php
**/
The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common problems.

No external libraries are needed to build this extension and it is available and compiled by default in PHP 5.0.0.

SPL provides a set of standard datastructure, a set of iterators to traverse over objects, a set of interfaces, a set of standard Exceptions, a number of classes to work with files and it provides a set of functions like spl_autoload_register()

/**
* https://www.php.net/manual/zh/class.iterator.php
**/

/**
* https://www.php.net/manual/zh/language.generators.overview.php
**/
``````

## TCP 和 UDP 的区别。

``````        UDP	TCP

https://segmentfault.com/a/1190000018582150``````

## 什么是 Socket 编程。

``````Socket 是对TCP/IP协议的封装，Socket本身并不是协议，而是一个调用接口（API），通过Socket，我们才能使用TCP/IP协议。

https://www.jianshu.com/p/f671d3895d13``````

## MySQL 索引。

``https://dev.mysql.com/doc/refman/8.0/en/optimize-overview.html``

## MySQL 事务。

``https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_transaction``

## MySQL 读写分离。

``````'mysql' => [
'host' => [
'192.168.1.1',
'196.168.1.2',
],
],
'write' => [
'host' => [
'196.168.1.3',
],
],
'sticky'    => true,
'driver'    => 'mysql',
'database'  => 'database',
'charset'   => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix'    => '',
],

https://laravel.com/docs/6.x/database``````

## 常见的 Redis 数据结构。

``https://www.runoob.com/redis/redis-data-types.html``

## Redis 集合(Set) 常用命令。

``https://www.runoob.com/redis/redis-sets.html``

## Redis cluster 原理。

``https://redis.io/topics/cluster-tutorial``

## Git Rebase

``````https://git-scm.com/book/en/v2/Git-Branching-Rebasing

https://docs.microsoft.com/en-us/azure/devops/repos/git/merging-with-squash?view=azure-devops``````

## Git 工作原理

``http://marklodato.github.io/visual-git-guide/index-zh-cn.html``

299 total views

## 1. 给定一个二维数组，数组每一行从左到右都是递增的，每一列也是递增的。请完成一个函数，输入为如上二维数组和一个整数，函数功能为判断该整数是否存在于数组中。时间复杂度尽可能的低。（请说明你的算法的复杂度。）

1 2 8 9

2 4 9 12

4 7 10 13

6 8 11 15

``````<?php

\$array = [
[1, 2, 8, 9],
[2, 4, 9, 12],
[4, 7, 10, 13],
[6, 8, 11, 15],
];

\$number = 9;

/**
* 最简单的方法就是遍历整个数组
* 时间复杂度 O(Row*Column-1)
*/
function findNumberInArray(\$array, \$number) {
foreach (\$array as \$rowArray) {
foreach (\$rowArray as \$value) {
echo \$value, " ";
if (\$number == \$value) {
return true;
}
}
}

return false;
}

/**
* 从二维数组的左下角开始逐行查找
* 时间复杂度 O(Row+Column-1)
*/
function findNumberInArray2(\$array, \$number) {
\$minRow = 0;
\$minColumn = 0;
\$maxRow = count(\$array) - 1;
\$maxColumn = count(\$array) - 1;

if (\$number < \$array || \$number > \$array[\$maxRow][\$maxColumn]) {
return false;
}

for (\$row = \$maxRow; \$row >= \$minRow; \$row--) {
for (\$column = \$minColumn; \$column <= \$maxColumn; \$column++) {
echo \$array[\$row][\$column], " ";
if (\$array[\$row][\$column] == \$number) {
return true;
}
if (\$array[\$row][\$column] > \$number) {
break;
}
if (\$array[\$row][\$column] < \$number) {
\$minColumn = \$column + 1;
}
}
}

return false;
}

/**
* 从二维数组的右上角开始逐行查找
* 时间复杂度 O(Row+Column-1)
*/
function findNumberInArray3(\$array, \$number) {
\$minRow = 0;
\$minColumn = 0;
\$maxRow = count(\$array) - 1;
\$maxColumn = count(\$array) - 1;

if (\$number < \$array || \$number > \$array[\$maxRow][\$maxColumn]) {
return false;
}

for (\$row = \$minRow; \$row <= \$maxRow; \$row++) {
for (\$column = \$maxColumn; \$column >= \$minColumn; \$column--) {
echo \$array[\$row][\$column], " ";
if (\$array[\$row][\$column] == \$number) {
return true;
}
if (\$array[\$row][\$column] > \$number) {
\$maxColumn = \$column - 1;
}
if (\$array[\$row][\$column] < \$number) {
break;
}
}
}

return false;
}

echo "/**
* 最简单的方法就是遍历整个数组
* 时间复杂度 O(Row*Column-1)
*/\n";
for (\$number = 0; \$number <= 15; \$number++) {
echo "find ", \$number, ": ";
findNumberInArray(\$array, \$number);
echo "\n";
}

echo "/**
* 从二维数组的左下角开始逐行查找
* 时间复杂度 O(Row+Column-1)
*/\n";
for (\$number = 0; \$number <= 15; \$number++) {
echo "find ", \$number, ": ";
findNumberInArray2(\$array, \$number);
echo "\n";
}

echo "/**
* 从二维数组的右上角开始逐行查找
* 时间复杂度 O(Row+Column-1)
*/\n";
for (\$number = 0; \$number <= 15; \$number++) {
echo "find ", \$number, ": ";
findNumberInArray3(\$array, \$number);
echo "\n";
}``````

## 2.把数组最开始的若干个元素搬到数组末尾，称为数组的旋转。给定一个递增数组的旋转数组，请完成一个函数，时间复杂度尽可能的低，输出该旋转数组的最小元素。并给出复杂度。

``````<?php

\$array = [4, 5, 6, 7, 8, 10, 1, 2, 3];

/**
* 使用 min() 函数
* 时间复杂度：O（N）
* 源码：https://github.com/php/php-src/blob/master/ext/standard/array.c
*/
echo min(\$array), "\n";

/**
* 使用二分查找法
* 时间复杂度：O(log2N)
*/
function findMinimumNumberInArray(\$array, \$start = 0, \$end = null) {
if (\$end == null) {
\$end = count(\$array) - 1;
}

if (\$start == \$end) {
return \$array[\$start];
}

\$middle = floor((\$start + \$end) / 2);

if (\$array[\$start] < \$array[\$end]) {
return findMinimumNumberInArray(\$array, \$start, \$middle);
} else {
return findMinimumNumberInArray(\$array, \$middle, \$end);
}
}

echo findMinimumNumberInArray(\$array), "\n";``````

## 3.输入一个字符串，输出该字符串中字符的所有组合。（不限编程语言，请注明你选择的语言）

``````<?php

\$string = "abc";
\$length = strlen(\$string);

/**
* 使用二进制表示不同的排列组合
*
* 0 0 1 a
* 0 1 0 b
* 0 1 1 ab
* 1 0 0 c
* 1 0 1 ac
* 1 1 0 bc
* 1 1 1 abc
*/
for (\$i = 1; \$i < 1 << \$length; \$i++) {
for (\$j = 0; \$j < \$length; \$j++) {
if (\$i & (1 << \$j)) {
echo \$string[\$j];
}
}
echo "\n";
}``````

440 total views,  1 views today

## 要点回顾

1. 方法 引用 是一 种 引用 方法 的 轻量级 语法， 形如： ClassName:: methodName。
2. 收集 器 可用 来 计算 流的 最 终值， 是 reduce 方法 的 模拟。
3. Java 8 提供 了 收集 多种 容器 类型 的 方式， 同时 允许 用户 自定义 收集器。

## 练习

Question 1:

https://leetcode.com/playground/KrzQMGgR

``````public static void subquestionA() {
List<String> collected = Stream.of("a", "b", "hello")
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(collected);
}

public static void subquestionB() {
int count = Stream.of(1, 2, 3)
.reduce(0, Integer::sum);
System.out.println(count);
}

public static void subquestionC() {
List<Integer> together = Stream.of(Arrays.asList(1,2), Arrays.asList(3,4))
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(together);
}``````

Question 2:

LongestName.java

``````public class LongestName {

private static Comparator<Artist> byNameLength = comparing(artist -> artist.getName().length());

public static Artist byReduce(List<Artist> artists) {
return artists.stream()
.reduce((acc, artist) -> {
return (byNameLength.compare(acc, artist) >= 0) ? acc : artist;
})
.orElseThrow(RuntimeException::new);
}

public static Artist byCollecting(List<Artist> artists) {
return artists.stream()
.collect(Collectors.maxBy(byNameLength))
.orElseThrow(RuntimeException::new);
}

}``````

WordCount.java

``````public class WordCount {

public static Map<String, Long> countWords(Stream<String> names) {
return names.collect(groupingBy(name -> name, counting()));
}

}``````

GroupingBy.java

``````public class GroupingBy<T, K> implements Collector<T, Map<K, List<T>>, Map<K, List<T>>> {

private final static Set<Characteristics> characteristics = new HashSet<>();
static {
}

private final Function<? super T, ? extends K> classifier;

public GroupingBy(Function<? super T, ? extends K> classifier) {
this.classifier = classifier;
}

@Override
public Supplier<Map<K, List<T>>> supplier() {
return HashMap::new;
}

@Override
public BiConsumer<Map<K, List<T>>, T> accumulator() {
return (map, element) -> {
K key = classifier.apply(element);
List<T> elements = map.computeIfAbsent(key, k -> new ArrayList<>());
};
}

@Override
public BinaryOperator<Map<K, List<T>>> combiner() {
return (left, right) -> {
right.forEach((key, value) -> {
left.merge(key, value, (leftValue, rightValue) -> {
return leftValue;
});
});
return left;
};
}

@Override
public Function<Map<K, List<T>>, Map<K, List<T>>> finisher() {
return map -> map;
}

@Override
public Set<Characteristics> characteristics() {
return characteristics;
}

}``````

Question 3:

Fibonacci.java

``````public class Fibonacci {

private final Map<Integer,Long> cache;

public Fibonacci() {
cache = new HashMap<>();
cache.put(0, 0L);
cache.put(1, 1L);
}

public long fibonacci(int x) {
return cache.computeIfAbsent(x, n -> fibonacci(n-1) + fibonacci(n-2));
}

}``````

301 total views

## 要点回顾

1. 使用为基本类型定制的Lambda表达式和Stream，如IntStream可以显著提升系统性能。
2. 默认方法是指接口中定义的包含方法体的方法，方法名有default关键字做前缀。
3. 在一个值可能为空的建模情况下，使用Optional对象能替代使用null值。

## 练习

Question 1:

``````/** 该接口表示艺术家的演出——专辑或演唱会 */
public interface Performance {

public String getName();

public Stream<Artist> getMusicians();

public default Stream<Artist> getAllMusicians() {
return getMusicians()
.flatMap(artist -> concat(Stream.of(artist), artist.getMembers()));
}

}``````

Question2:

``````public interface Parent {
default public boolean equals(Object object) {
return true;
}

default public int hashCode() {
return 1;
}
}``````
``````% javac Parent.java
Parent.java:2: error: default method equals in interface Parent overrides a member of java.lang.Object
default public boolean equals(Object object) {
^
Parent.java:6: error: default method hashCode in interface Parent overrides a member of java.lang.Object
default public int hashCode() {
^
2 errors``````

Question 3:

``````public class Artists {

private List<Artist> artists;

public Artists(List<Artist> artists) {
this.artists = artists;
}

public Optional<Artist> getArtist(int index) {
if (index < 0 || index >= artists.size()) {
return Optional.empty();
}
return Optional.of(artists.get(index));
}

public String getArtistName(int index) {
Optional<Artist> artist = getArtist(index);
return artist.map(Artist::getName)
.orElse("unknown");
}

}``````

555 total views

## 十月读书计划

“人生太短，普鲁斯特太长。”不如先读个节选版？

1.《追寻逝去的时光》读本，马塞尔·普鲁斯特， 广西师范大学出版社，2016

417 total views

## Java 8 函数式编程(2)

PS：如果你还没有了解过 Iterator 设计模式，请先去了解一下 Iterator 设计模式

## Stream

Stream 是用函数式编程方式在集合类上进行复杂操作的工具。

``````int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();``````

1. 使用 Collection.stream() 方法，创建 widgets 集合的流。
2. 使用 filter 操作，产生一个只包含红色 widgets 的流。
3. 使用 mapToInt 操作，转换成红色 widgets 的权重的流。
4. 使用 sum 操作，计算红色 widgets 的权重之和。

## 常用的流操作

 filter intermediate operation stateless map mapToInt mapToLong mapToDouble flatMap flatMapToInt flatMapToLong flatMapToDouble distinct stateful sorted peek limit skip takeWhile dropWhile forEach terminal operation forEachOrdered toArray reduce collect max count anyMatch allMatch noneMatch findFirst findAny

## 练习

Question 1:

``````    public static int addUp(Stream<Integer> numbers) {
return numbers.reduce(0, (acc, x) -> acc + x);
}

public static List<String> getNamesAndOrigins(List<Artist> artists) {
return artists.stream()
.flatMap(artist -> Stream.of(artist.getName(), artist.getNationality()))
.collect(toList());
}

public static List<Album> getAlbumsWithAtMostThreeTracks(List<Album> input) {
return input.stream()
.filter(album -> album.getTrackList().size() <= 3)
.collect(toList());
}``````

Question 2:

``int totalMembers = (int) artists.stream().flatMap(artist -> artist.getMembers()).count();``

Question 3:

``````a. 及早求值（Eager）- 返回 Stream
b. 惰性求值（Lazy）``````

Question 4:

``````a. 是 - 参数是函数
b. 否``````

Question 5:

``a. 没有副作用``

Question 6:

``````    public static int countLowercaseLetters(String string) {
return (int) string.chars()
.filter(Character::isLowerCase)
.count();
}``````

Question 7:

``````    public static Optional<String> mostLowercaseString(List<String> strings) {
return strings.stream()
.max(Comparator.comparing(StringExercises::countLowercaseLetters));
}``````

## 进阶练习

Question 1:

``````import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

/**
*/
public class MapUsingReduce {

public static <I, O> List<O> map(Stream<I> stream, Function<I, O> mapper) {
return stream.reduce(new ArrayList<O>(), (acc, x) -> {
// We are copying data from acc to new list instance. It is very inefficient,
// but contract of Stream.reduce method requires that accumulator function does
// not mutate its arguments.
// Stream.collect method could be used to implement more efficient mutable reduction,
// but this exercise asks to use reduce method.
List<O> newAcc = new ArrayList<>(acc);
return newAcc;
}, (List<O> left, List<O> right) -> {
// We are copying left to new list to avoid mutating it.
List<O> newLeft = new ArrayList<>(left);
return newLeft;
});
}

}``````

Question 2:

``````import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
*/
public class FilterUsingReduce {

public static <I> List<I> filter(Stream<I> stream, Predicate<I> predicate) {
List<I> initial = new ArrayList<>();
return stream.reduce(initial,
(List<I> acc, I x) -> {
if (predicate.test(x)) {
// We are copying data from acc to new list instance. It is very inefficient,
// but contract of Stream.reduce method requires that accumulator function does
// not mutate its arguments.
// Stream.collect method could be used to implement more efficient mutable reduction,
// but this exercise asks to use reduce method explicitly.
List<I> newAcc = new ArrayList<>(acc);
return newAcc;
} else {
return acc;
}
},
FilterUsingReduce::combineLists);
}

private static <I> List<I> combineLists(List<I> left, List<I> right) {
// We are copying left to new list to avoid mutating it.
List<I> newLeft = new ArrayList<>(left);
return newLeft;
}

}``````

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

345 total views

## Java Null Pointer Exception

Null Pointer Exception（NPE）是 Java 语言中非常常见的一个问题。

Article.java

``````public class Article
{
private Author author;

public Author getAuthor() {
return author;
}

public void setAuthor(Author author) {
this.author = author;
}
}``````

Author.java

``````public class Author
{
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}``````

Main.java

``````public class Main
{
public static void main(String[] args) {
Article article = null;

System.out.println(article.getAuthor().getName());
}
}``````

``````Exception in thread "main" java.lang.NullPointerException
at Main.main(Main.java:6)``````

``````public class Main1
{
public static void main(String[] args) {
Article article = null;

if (article != null && article.getAuthor() != null) {
System.out.println(article.getAuthor().getName());
} else {
System.out.println("Unknown");
}
}
}``````

``````import java.util.Optional;

public class Main2
{
public static void main(String[] args) {
Article article = null;

System.out.println(Optional.ofNullable(article).map(Article::getAuthor).map(Author::getName).orElse("Unknown"));
}
}``````

``````data class Article(var author: Author?);

data class Author(var name: String);

fun findArticle() : Article? {return null}

fun main() {
val article = findArticle();
println(article?.author?.name)
}``````

https://blog.udemy.com/java-null-pointer-exception/

https://kotlinlang.org/docs/reference/null-safety.html

390 total views,  1 views today