数组去重,你会几种方式?

前言

数据去重是项目中经常出现的应用场景,并且面试中可能也会问到,那么你会几种数组去重方式呢?

实战

使用额外空间去重
List<String> list = Arrays.asList("java", "html", "js", "sql", "java");

@Test
public void test8() {
		List<String> newList = new ArrayList<>();
		for (String el : list) {
				if(!newList.contains(el)) {
						newList.add(el);
				}
		}

		System.out.println(newList);
}
复制代码

优点:实现简单、并且在循环判断过程中可以增加额外操作

缺点:需要一个额外空间大小的数组,浪费空间,多行代码实现

Set集合自动去重
List<String> list = Arrays.asList("java", "html", "js", "sql", "java");

@Test
public void test8() {
  	Set<String> set = new HashSet<>(list);
  	List<String> newList = new ArrayList<>(set);

  	System.out.println(newList);
}
复制代码

优点:利用Set集合的不重复特性去重更简单

缺点:使用额外空间,需要来回转换,不太优雅

Java8一键去重(distinct)
List<String> list2 = Arrays.asList("java", "html", "js", "sql", "java");

 @Test
 public void test9() {
    // java8 stream-api去重
 		list2.stream()
 					.distinct()
 					.forEach(System.out::println);
 }
复制代码

优点:java8新特性,流式操作简单方便(和sql一样),代码优雅

缺点:无法在去重的过程中进行额外操作

distinct去重注意事项

既然这么好用,那distinct是通过什么去重的呢?如果是引用类型,是通过地址去重还是通过某些字段去重呢?

  • distinct去重失效示例代码

    List<Employee> list = Arrays.asList(
                new Employee( "小明", 18),
                new Employee( "赵六", 38),
                new Employee( "张三", 6),
                new Employee( "小明", 18)
        );
    
    class Employee {
        private String name;
        private Integer age;
    
        public Employee(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Employee{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    
    @Test
    public void test9() {
        list.stream()
          .distinct()
          .forEach(System.out::println);
    }
    复制代码

    控制台输出:

    Employee{name='小明', age=18}
    Employee{name='赵六', age=38}
    Employee{name='张三', age=6}
    Employee{name='小明', age=18}
    复制代码

    结果:使用自定义对象distinct无法去重,难道distinct无法作用引用类型吗?但是刚才的String也是引用类型,但是也可以去重。自定义的对象EmployeeString有什么区别吗?没错,就是hashcode()equals()方法,String已经重写了这两个方法,自定义的Employee没有重写这两个方法。

    注意:只要是涉及MapSet这种去重的集合,或者Java8的distinct去重,都是通过hashcode()equals来作为数据去重的依据,所以要注意重写这两个方法

  • 修改测试

    class Employee {
        private String name;
        private Integer age;
         
        ...
        
      	// 重写equals和hashcode方法
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Employee employee = (Employee) o;
            return Objects.equals(name, employee.name) &&
              Objects.equals(age, employee.age);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
      	
        ...
    }
    
    @Test
    public void test9() {
        list.stream()
          .distinct()
          .forEach(System.out::println);
    }
    复制代码

    控制台输出:

    Employee{name='小明', age=18}
    Employee{name='赵六', age=38}
    Employee{name='张三', age=6}
    复制代码

    重写hashcodeequals可以实现去重。

小总结

无论使用Set集合去重还是使用Java8的新特性stream流的distinct去重,都是通过hashcode()equals()自定义的策略进行去重。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享