Java8的这些集合骚操作,你掌握了嘛?

Wesley13
• 阅读 826

Java8时Lambda表达式的出现,将行为作为参数传递进函数的函数式编程,大大简化了之前冗杂的写法。

对于集合一类,我们来整理一下发生的变化吧。

Java8的这些集合骚操作,你掌握了嘛?

Iterable的forEach

Iterable接口就是所有可迭代类型的父接口,我们熟知的Collection接口就是继承自它。Java8接口默认方法以及Lambda表达式的出现,让我们在遍历元素时对元素进行操作变得格外简单。

下面的forEach方法就是Java8新增的,它接受一个Consumer对象,是一个消费者类型的函数式接口。

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

下面这段代码遍历输出每个元素。

    public void testForEach(){
        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        list.forEach(System.out::println);
    }

Iterator的forEachRemaining

java.util.Iterator是用于遍历集合的迭代器,接口定义如下:

public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

default方法是Java8接口中新增的,forEachRemaining方法接收一个Consumer,我们可以通过该方法简化我们的遍历操作:

    /**
     * Java8 为Iterator新增了 forEachRemaining(Consumer action) 方法
     */
    public static void main(String[] args) {

        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Iterator<Integer> iterator = list.iterator();
        iterator.forEachRemaining(System.out::println);
    }

Collection的removeIf

Java8为Collection增加了默认的removeIf方法,接收一个Predicate判断,test方法结果为true,就移除对应的元素。

    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            // 判断元素是否需要被移除
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }

下面这段代码移除列表中的偶数元素。

    public void testRemoveIf() {
        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        list.removeIf(x -> x % 2 == 0);
        list.forEach(System.out::println);
    }

Stream操作

具体使用可以参照

    public void testStream(){
        IntStream stream = IntStream.builder().add(1).add(2).add(3).build();
        int max = stream.max().getAsInt();
        System.out.println(max);
    }

List的replaceAll

Java8为List接口增加了默认的replaceAll方法,需要UnaryOperator来替换所有集合元素,UnaryOperator是一个函数式接口。

    default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

下面这个示例为每个元素加上3。

    public void testReplaceAll(){
        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        list.replaceAll(x -> x + 3);
        list.forEach(System.out::println);
    }

List的sort

Java8为List接口增加了默认的sort方法,需要Comparator对象来控制元素排,我们可以传入Lambda表达式。

    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

下面这个例子将list逆序。

    public void testSort() {
        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        list.sort((x, y) -> y - x);
        System.out.println(list);
    }

Map的ForEach

Map接口在Java8同样也新增了用于遍历的方法:

    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }

该方法接收一个二元的参数,分别对应key和value:

    private void print(Map<Integer,String> map){
        map.forEach((x , y )-> {
            System.out.println("x -> " + x + ", y -> " + y);
        });
    }

为了接下来测试方便,数据先准备一下:

    Map<Integer, String> map = new HashMap<>();

    {
        map.put(1, "hello");
        map.put(2, "summer");
        map.put(3, "day");
        map.put(4, "tqbx");
    }

Map的remove

Java8新增了一个remove(Object key, Object value)方法。

    default boolean remove(Object key, Object value) {
        // key存在且key对应的value确实是传入的value才移除
        Object curValue = get(key);
        if (!Objects.equals(curValue, value) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        remove(key);
        return true;
    }

移除key为3且value为day的元素。

    @Test
    public void testRemove(){
        map.remove(3,"day");
        print(map);
    }

Map的compute相关方法

Object compute(Object key, BiFunction remappingFunction):该方法使用remappingFunction根据key-value对计算一个新value,情况如下:

  • 只要新value不为null,就使用新value覆盖原value。
  • 如果原value不为null,但新value为null,则删除原key-value对。
  • 如果原value、新value同时为null那么该方法不改变任何key-value对,直接返回null。

Object computeIfAbsent(Object key, Function mappingFunction):

  • 如果传给该方法的key参数在Map中对应的value为null,则使用mappingFunction根据key计算个新的结果。
  • 如果计算结果不为null,则用计算结果覆盖原有的value。
  • 如果原Map原来不包括该key,那么该方法可能会添加一组key-value对。

Object computeIfPresent(Object key, BiFunction remappingFunction):

  • 如果传给该方法的key参数Map中对应的value不为null,该方法将使用remappingFunction根据原key、value计算一个新的结果。

  • 如果计算结果不为null,则使用该结果覆盖原来的value。

  • 如果计算结果为null,则删除原key-value对。

    @Test
    public void testCompute() {
        //key==2 对应的value存在时,使用计算的结果作为新value
        map.computeIfPresent(2, (k, v) -> v.toUpperCase());
        print(map);
    
        //key==6 对应的value为null (或不存在)时,使用计算的结果作为新value
        map.computeIfAbsent(6, (k) -> k + "haha");
        print(map);
    }
    

Map的getOrDefault

    default V getOrDefault(Object key, V defaultValue) {
        V v;
        // key存在或 value存在,则返回对应的value,否则返回defaultValue
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }


    @Test
    public void testGetOrDefault(){
        // 获取指定key的value,如果该key不存在,则返回default
        String value = map.getOrDefault(5, "如果没有key==5的value,就返回这条信息");
        System.out.println(value);
    }

Map的merge

    default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        // 先获取原值
        V oldValue = get(key);
        // 原值为null,新值则为传入的value,不为null,则使用function计算,得到新值
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        // 新值如果为null,则移除原key-value对
        if(newValue == null) {
            remove(key);
        } else {
            // 不为null,则替换之
            put(key, newValue);
        }
        // 返回新值
        return newValue;
    }


    @Test
    public void testMerge(){
        // key为2 的值 加上 +add
        map.merge(2," + add",(oldval, newVal) -> oldval + newVal);
        print(map);
    }

Map的putIfAbsent

    default V putIfAbsent(K key, V value) {
        // 得到原值
        V v = get(key);
        // 原值为null,则替换新值
        if (v == null) {
            v = put(key, value);
        }
        // 返回原值
        return v;
    }


    @Test
    public void testPutIfAbsent(){
        // key = 10 对应的value不存在, 则用101010 覆盖
        String s1 = map.putIfAbsent(10, "101010");
        System.out.println(s1);
        print(map);
        System.out.println("============================");
        // key = 2 对应的value存在且为summer,返回summer
        String s2 = map.putIfAbsent(2, "2222");
        System.out.println(s2);
        print(map);
    }

输出结果

null
x -> 1, y -> hello
x -> 2, y -> summer
x -> 3, y -> day
x -> 4, y -> tqbx
x -> 10, y -> 101010
============================
summer
x -> 1, y -> hello
x -> 2, y -> summer
x -> 3, y -> day
x -> 4, y -> tqbx
x -> 10, y -> 101010

Map的replace相关方法

    @Test
    public void testReplace(){
        //boolean 将指定的 1 -> hello 键值对的value替换为hi
        map.replace(1,"hello","hi");
        print(map);
        System.out.println("============================");
        //V 指定key对应的value替换成新value
        map.replace(2,"天乔巴夏");
        print(map);
        System.out.println("============================");
        //void 对所有的key和value 进行计算,填入value中
        map.replaceAll((k,v)-> k + "-" + v.toUpperCase());
        print(map);
    }

输出结果:

x -> 1, y -> hi
x -> 2, y -> summer
x -> 3, y -> day
x -> 4, y -> tqbx
============================
x -> 1, y -> hi
x -> 2, y -> 天乔巴夏
x -> 3, y -> day
x -> 4, y -> tqbx
============================
x -> 1, y -> 1-HI
x -> 2, y -> 2-天乔巴夏
x -> 3, y -> 3-DAY
x -> 4, y -> 4-TQBX

原文:https://www.cnblogs.com/summerday152/p/14129448.html

如果觉得本文对你有帮助,可以关注一下我公众号,回复关键字【面试】即可得到一份Java核心知识点整理与一份面试大礼包!另有更多技术干货文章以及相关资料共享,大家一起学习进步!

Java8的这些集合骚操作,你掌握了嘛?

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Karen110 Karen110
3年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这