专栏首页我要变牛震惊Guava竟然有"坑"

震惊Guava竟然有"坑"

杂谈之内卷

最近在几个技术交流群经常看到大家讨论开发行业内卷,什么是内卷呢?一句话,大家越来越努力,越来越累,但是幸福感和收获并没有增加,甚至实际上是下降了。

举个大城市西安的例子

为了让小孩能上更好的小学,家长都发疯一样买学区房,但是好学校一年的招生名额是有限的,不管学区房有多贵,并不能增加招生名额。比如某名校一年收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. 过滤后列表的迭代器不支持remove()操作
  2. add不符合过滤条件的元素,会抛出IllegalArgumentException
  3. 当过滤后列表中的元素不再满足过滤条件时,会影响到已经过滤出来的列表出于程序员的本能,决定还是看下源码心里更踏实。核心源码如下:
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));

方案三(可行,改用Java8的过滤器):

List<Person> personAgeGt30 = names.stream().filter((Predicate<Person>) p -> p.age >30).collect(Collectors.toList());

方案四(可行,改用Guava的连贯接口,IDEA编辑器会提示你替换成Java8 API)

ImmutableList<Person> personAgeGt30 = FluentIterable.from(names).filter(p -> p.age > 30).toList();

上述方案中,支持java8的生产环境推荐方案三,不支持java8的生产环境推荐方案二。

总结

其实,Java语言中类似的坑还有很多,比如:

  • 1.Arrays.asList()生成的列表是不可变的。
  • 2.subList生成的子列表,对原列表元素的修改,会导致子列表的遍历、增加、删除抛出ConcurrentModificationException,
  • 3.subList对子列表的修改会影响到原列表数据
  • 4.修改Map的keySet()方法和values()生成的容器,都会影响Map本身。

总之,使用任何API之前多看看源码,至少看看源码的注释。

本文分享自微信公众号 - 你呀不牛(notNiu),作者:stevenniu

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 震惊!if else 竟然同时输出!

    pcntl_fork 函数是php多进程扩展的一个函数,用于创建一个新进程执行,其返回值为 主进程id和0 或者 -1(错误)

    仙士可
  • 震惊!中华夜壶竟后继有人!

    本文章仅供学习交流使用,文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!

    用户1789928
  • 震惊!他竟然用回归分析做这种事

    今年的双十一已然过去,之前文章里有提到过我预测了天猫的成交额为2675.55亿元,和真实值的数据非常地相近,有朋友就问我是如何预测的,方法其实很简单,多项式回归...

    老肥码码码
  • 字幕组 | 震惊!你竟然是这样的区块链!

    大数据文摘
  • 震惊!程序员竟然经常浏览这些网站

    谭庆波
  • 震惊!90%的简历,竟然都犯过这些错误……

    投递简历后,却石沉大海。这种心情就好像给喜欢的人写了一封情书,对方却没有任何回复。你说,扎不扎心?

    猴子聊数据分析
  • 震惊!竟然有人研究精液微生物的生物地理分布

    Frontiers in Microbiology 于2019.1.31号在线刊出一篇文章,研究了中国人精液中微生物的生物地理学分布。不知道为什么,看到这个标题...

    Listenlii-生物信息知识分享
  • 震惊:编程或者软件开发竟然不算知识?

    自从上次看了业界大神阮一峰发的那篇文章之后,给我的印象非常的深刻,一直想写文章跟大家交流和探讨一下,那就是:软件开发到底算不算知识呢?

    非著名程序员
  • 震惊!北京一男子竟然用swoole做了这种事!

    自己挖的坑自己填吧,今天咱就简单地利用swoole(实际上用我撸的那个沙雕一样的ti-rpc,上手会快一些)去实现这种【大量耗时数据导出】需求。但是,我还是偷了...

    老李秀
  • 震惊!这样终止线程,竟然会导致服务宕机?

    或许你已经发现了,上面这段代码使用了 Thread.stop() 来终止线程,在 Java 程序中是不允许这样终止线程的。什么?你问为什么不能这样?

    Java中文社群-磊哥
  • 分享 | 震惊,机器学习居然有这些事

    机器学习是一类算法的总称,这些算法企图从大量历史数据中挖掘出其中隐含的规律,并用于预测或者分类,更具体的说,机器学习可以看作是一个函数,输入是样本数据,输出是期...

    潘永斌
  • 震惊!东某吃葡萄时竟然吃出一道算法题🤔

    有三种葡萄,每种分别有a, b, c颗,现在有三个人,第一个人只吃第一种和第二种葡萄,第二个人只吃第二种和第三种葡萄,第三个人只吃第一种和第三种葡萄。

    labuladong
  • 悠爸玩数学 | 冲破宇宙的折纸

    用户7378374
  • 震惊!无人问津的文章竟然是这样写出来的No.98

    大蕉
  • MyBatis原生批量插入的坑与解决方案!

    前面的文章咱们讲了 MyBatis 批量插入的 3 种方法:循环单次插入、MyBatis Plus 批量插入、MyBatis 原生批量插入,详情请点击《MyBa...

    Java中文社群-磊哥
  • 【编程课堂】震惊!小 bug 引发大灾难,0.1 + 0.2 的结果竟然是……

    各位观众点进标题看文章的时候,我已经准备打包行李去UC报道啦~ 冷笑话结束,嗯,说正事。 请大家思考一下在 python 控制台输入 0.1 + 0.2 ==...

    Crossin先生
  • 惊!史上最佳GAN现身,超真实AI假照片,行家们都沸腾了

    AMAZING、Incredible、Very impressive、A huge fan……

    量子位
  • (震惊)机电学生竟然帮助建筑同学做人工智能大作业!

    本来说要让我去搞人工智能大作业,我一开始是拒绝的,因为我作为一个传统的机械电子工程专业的学生,怎么可以不务正业呢?同时感觉到现在建筑学教育也开始这么的浮夸了么,...

    UDM Lab
  • 惊呆了,spring中竟然有12种定义bean的方法

    在庞大的java体系中,spring有着举足轻重的地位,它给每位开发者带来了极大的便利和惊喜。我们都知道spring是创建和管理bean的工厂,它提供了多种定义...

    CSDN技术头条

扫码关注云+社区

领取腾讯云代金券