最近在几个技术交流群经常看到大家讨论开发行业内卷,什么是内卷呢?一句话,大家越来越努力,越来越累,但是幸福感和收获并没有增加,甚至实际上是下降了。
举个大城市西安的例子
为了让小孩能上更好的小学,家长都发疯一样买学区房,但是好学校一年的招生名额是有限的,不管学区房有多贵,并不能增加招生名额。比如某名校一年收250个小学生,就算周边学区房涨价到3万一平米,还是一年收250个学生,但家长们为了让孩子入学,不得不接受3万一平米的单价,去买一套老破小居住,说不定还要把原先的大房子卖掉,因为限购了,名下只能有一套房。
更可怕的是,学区房政策是会变的,说不定每年都变,所以你就算买了学区房也不一定能够顺利上学。比如,周边适龄儿童有400个人,可是招生名额还是只有250,那就意味着肯定有150人无法入学。那怎么办呢?学校就搞了个排名,有本地户籍且人户一致的优先入学,有本地户籍人户不一致的排第二,没有本地户籍但有房产证的排第三……如果以上这些都卡不住你怎么办呢?很简单,多校划片,最终能上哪个学校,电脑随机抽签。
深深的恶意
但事实上考大学一样是内卷游戏,内卷给人一种恐慌的感觉,大家在恐惧的驱使下,竭尽所能争夺资源,可是资源有限,大家越是争夺,资源损坏越大,甚至无序的竞争会带来毁灭性结局。可是你不争,就被别人得了便宜,被人骂SB。
社会发展到今天,凭现在的生产力,足以让所有人过上衣食无忧的生活。但是由于分配问题,由于资本的压榨本质,使得大部分人并没有因为生产力和科技的发展获得相应的幸福感。内卷的结果,是资本可以获得更加廉价的劳动力,资本增值更快。但是劳动力本身却更苦了。尤其是在这个科技和知识是第一生产力的时代,内卷并不利于社会进步。因为知识生产需要一个比较宽松的社会环境。社会福利越好,知识生产反而会越佳。那种残酷竞争所带来的不安全感,实际上是不利于科技进步的。内卷状态下的知识生产者,是非常焦虑的。相应的,知识学习者也是极度焦虑,这样的学习效果其实并不好。这更何况,这种过分的竞争极大的降低了人们的安全感和幸福感。……我所想象的理想世界是,每个人可以在解决温饱的前提下,做自己喜欢做的工作,焕发出最大的工作热情,从而促进社会进步。当然,这只是理想。
我不知道如何改变内卷的命运,但可以尽量在内卷的前头早做准备,2020年虽然是非常艰难的一年,但相对于未来而言,反倒可能是最容易的一年了,因为将来随着内卷的深入,一定会越来越困难的,别到时候又后悔错过了2020年的机会。种一个颗树最好的时间一个是十年前,另一个就是现在。机会也永远留给有准备的人,你不去学习不去进步的话,到时候又要做负责接盘的下家了。
最近,团队里边一个兄弟突然叫我:快来看,有个奇怪的事情,无法解释… 跑过去一看,是这么一段代码:
private static class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return name + ":" + age;
}
}
@Test
public void test_collections2_filter() {
Person lxy = new Person(35, "lxy");
Person xhf = new Person(34, "xhf");
Person nws = new Person(31, "nws");
List<Person> names = Lists.newArrayList(lxy, xhf, nws);
Collection<Person> personAgeOver30 = Collections2.filter(names, p -> p.age > 30);
System.out.println(personAgeOver30);//[lxy:35, xhf:34, nws:31]
nws.setAge(25);
System.out.println(personAgeOver30);//[lxy:35, xhf:34]
}
确实是比较奇怪,personAgeGt30中的元素怎么会少了一个呢?本着任何表现奇怪的程序都有其背后原因的指导思想,打开了Guava Collections2类的源代码。其实,源代码的注释已经解释得非常清楚了:returned collection is a live view of {@code unfiltered}; changes to one affect the other.
/**
* Returns the elements of {@code unfiltered} that satisfy a predicate. The returned collection is
* a live view of {@code unfiltered}; changes to one affect the other.
*
* <p>The resulting collection's iterator does not support {@code remove()}, but all other
* collection methods are supported. When given an element that doesn't satisfy the predicate, the
* collection's {@code add()} and {@code addAll()} methods throw an {@link
* IllegalArgumentException}. When methods such as {@code removeAll()} and {@code clear()} are
* called on the filtered collection, only elements that satisfy the filter will be removed from
* the underlying collection.
*
* <p>The returned collection isn't threadsafe or serializable, even if {@code unfiltered} is.
*
* <p>Many of the filtered collection's methods, such as {@code size()}, iterate across every
* element in the underlying collection and determine which elements satisfy the filter. When a
* live view is <i>not</i> needed, it may be faster to copy {@code Iterables.filter(unfiltered,
* predicate)} and use the copy.
*
* <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>, as documented at
* {@link Predicate#apply}. Do not provide a predicate such as {@code
* Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. (See {@link
* Iterables#filter(Iterable, Class)} for related functionality.)
*
* <p><b>{@code Stream} equivalent:</b> {@link java.util.stream.Stream#filter Stream.filter}.
*/
Collections2.filter方法返回的只是原有列表的一个视图。所以:改变被过滤列表会影响过滤后列表,反之 亦然。并且我们从这段文字中还能get到下面几个注意事项:
1. add方法:
public boolean add(E element) {
//不符合过滤条件抛IllegalArgumentException的原因
checkArgument(predicate.apply(element));
return unfiltered.add(element);
}
不支持通过迭代器删除的原因:
public abstract class UnmodifiableIterator<E> implements Iterator<E> {
/** Constructor for use by subclasses. */
protected UnmodifiableIterator() {}
/**
* Guaranteed to throw an exception and leave the underlying data unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public final void remove() {
throw new UnsupportedOperationException();
}
打印结果变化的原因:
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}
@Override
public Iterator<E> iterator() {
return Iterators.filter(unfiltered.iterator(), predicate);
}
问题已经弄清楚了,怎么修改这个问题呢?
干脆不用guava,
List<Person> names = Lists.newArrayList(lxy, xhf, nws);
ArrayList<Person> persons = new ArrayList<>();
for (Person p : names) {
if(p.age > 30) {
persons.add(p);
}
}
用个容器再包装一下:
Collection<Person> personAgeGt30 = new ArrayList<(Collections2.filter(names, p -> p.age > 30));
List<Person> personAgeGt30 = names.stream().filter((Predicate<Person>) p -> p.age >30).collect(Collectors.toList());
ImmutableList<Person> personAgeGt30 = FluentIterable.from(names).filter(p -> p.age > 30).toList();
上述方案中,支持java8的生产环境推荐方案三,不支持java8的生产环境推荐方案二。
其实,Java语言中类似的坑还有很多,比如:
总之,使用任何API之前多看看源码,至少看看源码的注释。