关于Java8新特性Lamb表达式简单了解

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zombres/article/details/78905340

最近接了新的项目,jdk使用的是1.8+,但代码中完全没有用到java8的特性,于是着手精简了下代码,也抽空总结了一下给自己备忘。

先罗列一下我今天看到的一些相对与Java7的变化:

部分新特性

  1. 新增java.util.function包,包中都是使用注解@FunctionInterface修饰的接口,而这种接口就是所谓的函数式接口,一般使用这种接口作为参数的方法,就可以使用Lamb表达式作为值传入。
  2. 新增java.util.stream包,这个stream的概念和IO包中的流是完全不同的概念,这个Stream 是对集合(Collection)对象功能的增强,可以参考另一篇专门的文章传送门
  3. 接口中可以实现具体的方法了,当然还是和抽象类有区别的,接口中只能实现静态方法和default方法,这个据说是为了扩展集合相关接口想出来的方法,这个理解起来比较简单,可以参考这篇文章就可以了。
  4. 今天学到的重点:Comparator接口中新增了一系列的default方法,这些方法基本都返回一个Comparator实例,而这个实例就是用于列表的排序,方便的是,List接口本身实现了一个default的的sort方法,参数就是一个Comparator。

下面是一些简单的入门级别例子:

关于列表排序

List<Integer> list2 = Arrays.asList(1,2,3,4,5,6);
list2.sort((t1, t2) -> t2-t1);	//重点
System.out.println(list2.stream().map((m) -> m.toString()).collect(Collectors.joining(",")));

这段代码中,第二行是重点,sort方法的参数是一个Comparator,这里使用一个Lamb表达式来实现了比较规则,这个可以分开来写,理解起来更简单一点。

List<Integer> list2 = Arrays.asList(1,2,3,4,5,6);
Comparator<Integer> comparator1 = (t1, t2) -> t2-t1;
list2.sort(comparator1);
//list2.sort(comparator1.reversed());

这样写更能明白整个过程,注释掉的第四行,意思是可以对上面那个Comparator对排序规则进行反转,这个reversed方法也是一个Comparator的default方法,很实用。
其实Comparator内置的一些default方法完全能实现简单排序规则

List<Integer> list2 = Arrays.asList(1,2,3,4,5,6);
Comparator<Integer> comparator1 = Comparator.comparingInt(Integer::intValue);
list2.sort(comparator1);

第二行的这种写法,就是使用Comparator中的default方法comparingInt来对整型的值进行排序。而双冒号的写法大概意思是动态调用其对象中的某个方法。我们写个自定义对象来看一下书写方式。

public static void main(String[] atr){
        Test test = new Test();
        List<Person> list = Arrays.asList(
	        test.new Person("a", 10), 
	        test.new Person("b", 23), 
	        test.new Person("c", 25));

        Comparator<Person> comparator = Comparator.comparingInt(Person::getAge);
        //list.sort(comparator.reversed());

        list.forEach(obj -> System.out.println(obj.toString()));
    }

    class Person{
        String name;
        int age;

        public Person(String name, int age){
            this.name = name;
            this.age = age;
        }

        public int getAge(){
            return this.age;
        }
    }

为了测试方便,这里实现了一个内部类,main方法中的用这个内部类的对象填充了一个list,这行代码Comparator<Person> comparator = Comparator.comparingInt(Person::getAge);就是实现了一个比较器,对年龄age进行自然排序,当然如果要倒序的化,使用comparator.reversed()方法即可。
实际工作中还有组合条件进行排序的情况,不过JDK团队想的特别周到,看下面的实现。

Test test = new Test();
List<Person> list = Arrays.asList(
	        test.new Person("a", 10), 
	        test.new Person("b", 25), 
	        test.new Person("c", 25));

Comparator<Person> comparator = Comparator.comparingInt(Person::getAge);
Comparator<Person> comparatorName = Comparator.comparing(Person::getName);
     
list.sort(comparator.reversed().thenComparing(comparatorName));

list.forEach(obj -> System.out.println(obj.toString()));

实现多个比较器就可以了,这基本能满足大部分应用场景了。


关于集合之间转换

1. 集合流过滤器的实现并转List输出:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> list2 = list.stream().filter(o -> o%2 == 0).collect(Collectors.toList);
2. 列表与数组相互转换
// 数组转列表
String[] arrays = new String[]{"a", "b", "c"};
List<String> listStrings = Stream.of(arrays).collector(Collectors.toList()) // toSet()
List<String> listStrings_2 = Arrays.stream(arrays).collector(Collectors.toList()) // 作用和上一行一样

// 列表转数组
String[] ss = listStrings.stream().toArray(String[]::new);
String[] sss = listStrings.toArray(new String[listStrings.size()]);
3. 列表转Map
// 常用方式
Map<String, String> map = accounts.stream()
					.collect(Collectors.toMap(Account::getId, Account::getUsername));

// 收集成实体本身map
 Map<Long, Account> map =  accounts.stream()
 				.collect(Collectors.toMap(Account::getId, account -> account));

// account -> account是一个返回本身的lambda表达式,其实还可以使用Function接口中的一个默认方法代替,使整个方法更简洁优雅:
Map<Long, Account> map = accounts.stream()
				.collect(Collectors.toMap(Account::getId, Function.identity()));

/** 上面的实现如果id有重复情况会报错(java.lang.IllegalStateException: Duplicate key)。
*  toMap有个重载方法,可以传入一个合并的函数来解决key冲突问题:(如果有重复的key,则保留key1,舍弃key2)
*/
Map<Long, Account> map = accounts.stream()
			.collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2));

// toMap还有另一个重载方法,可以指定一个Map的具体实现,来收集数据:
LinkedHashMap<> map =  accounts.stream()
		.collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2, LinkedHashMap::new));

Stream 创建的N种方式

从上面的例子看出,关于列表的流式操作还是很方便的,所以我整理流一下能从各种数据生成流的方式来方法日常使用:

// Stream.of 可变参数
Stream<String> stream1 = Stream.of("A", "B", "C");

// Stream.of 数组或者直接用Arrays的工具方法
String[] values = new String[]{"A", "B", "C"};
Stream<String> stream2 = Stream.of( values );   
Stream<String> stream3 = Arrays.stream(values);

// 集合的实现方式不用多说
List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream4 = list.stream();
Set<String> set = new HashSet<>(Arrays.asList("A", "B", "C"));
Stream<String> stream5 = set.stream();
Map<String, String> map = new HashMap<>();
Stream<String> stream6 = map.values().stream();

// Pattern
String value = "A B C";
Stream<String> stream8 = Pattern.compile("\\W").splitAsStream(value);

// 文件读取
Stream<String> stream9 = Files.lines(Paths.get("d:/data.txt"));

参考文章:

展开阅读全文

没有更多推荐了,返回首页