jdk-8新特性

jdk-8新特性

Lambda表达式

这个大家应该都会用,就不多赘述了

在jdk1.8 中为接口增强,提供了静态方法和默认方法 用于扩展方便

函数式接口

​ 这里我们需要知道一个注解**@FunctionalInterface** 一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。不过,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。

​ 我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽

象方法的参数列表和返回值类型。因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口。

常用内置函数式接口介绍

它们主要在 java.util.function 包中。下面是最常用的几个接口。

  1. Supplier接口
@FunctionalInterface
public interface Supplier<T> { 
    public abstract T get();
}

​ java.util.function.Supplier 接口,它意味着"供给" , 对应的Lambda表达式需要“对外提供”一个符合泛型类

型的对象数据。

​ 供给型接口,通过Supplier接口中的get方法可以得到一个值,无参有返回的接口。

  1. Consumer接口

    @FunctionalInterface
    public interface Consumer<T> { 
        public abstract void accept(T t);
    }
    

    ​ java.util.function.Consumer 接口则正好相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛

    型参数决定。

    Consumer消费型接口,可以拿到accept方法参数传递过来的数据进行处理, 有参无返回的接口。

    ​ 如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费一个数据的时候,首先做一个操

    作,然后再做一个操作,实现组合。而这个方法就是 Consumer 接口中的default方法 andThen 。

  2. Function接口

    @FunctionalInterface 
    public interface Function<T, R> { 
    	public abstract R apply(T t); 
    } 
    

    ​ java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,

    后者称为后置条件。有参数有返回值。

    ​ Function转换型接口,对apply方法传入的T类型数据进行处理,返回R类型的结果,有参有返回的接口

  3. Predicate接口

    @FunctionalInterface 
    public interface Predicate<T> { 
    	public abstract boolean test(T t); 
    }
    Predicate接口用于做判断,返回boolean类型的值
    

    有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用

    java.util.function.Predicate 接口。

方法引用

双冒号 :: 写法,这被称为“方法引用”,是一种新的语法。

符号说明 : 双冒号为方法引用运算符,而它所在的表达式被称为方法引用

应用场景 : 如果Lambda所要实现的方案 , 已经有其他方法存在相同方案,那么则可以使用方法引用。

常见引用方式

方法引用在JDK 8中使用方式相当灵活,有以下几种形式:

  1. instanceName::methodName 对象::方法名

  2. ClassName::staticMethodName 类名::静态方法

  3. ClassName::methodName 类名::普通方法

  4. ClassName::new 类名::new 调用的构造器

  5. TypeName[]::new String[]::new 调用数组的构造器

对象名::引用成员方法

这是最常见的一种用法,与上例相同。如果一个类中已经存在了一个成员方法,则可以通过对象名引用成员方法,代

码为:

// 对象::实例方法

@Test
public void test01() { 
Date now = new Date(); 
Supplier<Long> supp = () -> { 
return now.getTime(); 
	};
System.out.println(supp.get()); 
Supplier<Long> supp2 = now::getTime; 
System.out.println(supp2.get()); 
	}

方法引用的注意事项

  1. 被引用的方法,参数要和接口中抽象方法的参数一样

  2. 当接口抽象方法有返回值时,被引用的方法也必须有返回值

类名::引用静态方法

由于在 java.lang.System 类中已经存在了静态方法 currentTimeMillis ,所以当我们需要通过Lambda来调用该

方法时,可以使用方法引用 , 写法是:类名::静态方法

@Test 
public void test02() { 
	Supplier<Long> supp = () -> { 
	return System.currentTimeMillis(); 
	};
	System.out.println(supp.get());
    
	Supplier<Long> supp2 = System::currentTimeMillis; 
	System.out.println(supp2.get()); 
	}

类名::引用实例方法

Java面向对象中,类名只能调用静态方法,类名引用实例方法是有前提的,实际上是拿第一个参数作为方法的调用

者。

// 类名::实例方法 
@Test 
public void test03() { 
	Function<String, Integer> f1 = (s) -> { 
	return s.length(); 
};
System.out.println(f1.apply("abc")); 

Function<String, Integer> f2 = String::length; 
System.out.println(f2.apply("abc")); 

BiFunction<String, Integer, String> bif = String::substring; 
String hello = bif.apply("hello", 2); 
System.out.println("hello = " + hello); 

}

类名::new引用构造器

由于构造器的名称与类名完全一样。所以构造器引用使用 类名称::new 的格式表示。首先是一个简单的 Person 类:

public class Person { 
	private String name; 
public Person(String name) { 
	this.name = name; 
}
	public String getName() { 
return name; 
	} 
}
// 类名::new 
@Test 
public void test04() { 
	Supplier<Person> sup = () -> { 
	return new Person(); 
};
	System.out.println(sup.get()); 

	Supplier<Person> sup2 = Person::new; 
	System.out.println(sup2.get()); 

	BiFunction<String, Integer, Person> fun2 = Person::new; 
		System.out.println(fun2.apply("张三", 18)); 

}

数组::new引用数组构造器

数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同。

// 类型[]::new 
@Test 
public void test05() { 
	Function<Integer, String[]> fun = (len) -> { 
	return new String[len]; 
};
	String[] arr1 = fun.apply(10); 
	System.out.println(arr1 + ", " + arr1.length); 
	
	Function<Integer, String[]> fun2 = String[]::new; 
	String[] arr2 = fun.apply(5); 
	System.out.println(arr2 + ", " + arr2.length); 	
}

方法引用是对Lambda表达式符合特定情况下的一种缩写,它使得我们的Lambda表达式更加的精简,也可以理解为Lambda表达式的缩写形式 , 不过要注意的是方法引用只能"引用"已经存在的方法

stream流

今天来总结下jdk8的新特性stream流,这个是很久以前我就系统性的学过了,并也实际在项目中运用过,今天太闲了,再总结下_我也顺便再复习一下~~~

友情提示:这个大家用过的就赶紧去学一下吧,你会发现会stream流真的太好用了 嘻嘻嘻嘻嘻嘻!!!

上干货!!!

Stream是流式思想,相当于工厂的流水线,对集合中的数据进行加工处理

​ 掌握根据Collection获取流

​ 掌握Stream中的静态方法of获取流

​ java.util.stream.Stream 是JDK 8新加入的流接口。

​ 获取一个流非常简单,有以下几种常用的方式:

  • 所有的 Collection 集合都可以通过 stream 默认方法获取流;

  • Stream 接口的静态方法 of 可以获取数组对应的流。

方式一:Collection 集合都可以通过 stream 默认方法获取流;

java.util.Map 接口不是 Collection 的子接口,所以获取对应的流需要分key、value或entry等情况

public static void main(String[] args) {
// Map获取流
Map<String, String> map = new HashMap<>();
// ... 
Stream<String> keyStream = map.keySet().stream(); 
Stream<String> valueStream = map.values().stream();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream(); 
}

方式2 : Stream中的静态方法 of 获取流

由于数组对象不可能添加默认方法,所以 Stream 接口中提供了静态方法 of ,使用很简单

String[] arr = {"aa", "bb", "cc"};
Stream<String> stream7 = Stream.of(arr);
  • 备注: of 方法的参数其实是一个可变参数,所以支持数组。

学习了两种获取流的方式:

  1. 通过Collection接口中的默认方法Stream stream()

  2. 通过Stream接口中的静态of方法

Stream常用方法

Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

中间操作符、终止操作符

中间操作符


流方法含义示例
filter用于通过设置的条件过滤出元素List strings = Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,“”, “jkl”);List filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
distinct返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流。List numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
limit会返回一个不超过给定长度的流。List strings = Arrays.asList(“abc”, “abc”, “bc”, “efg”, “abcd”,“jkl”, “jkl”);List limited = strings.stream().limit(3).collect(Collectors.toList());
skip返回一个扔掉了前n个元素的流。List strings = Arrays.asList(“abc”, “abc”, “bc”, “efg”, “abcd”,“jkl”, “jkl”);List skiped = strings.stream().skip(3).collect(Collectors.toList());
map接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)。List strings = Arrays.asList(“abc”, “abc”, “bc”, “efg”, “abcd”,“jkl”, “jkl”);List mapped = strings.stream().map(str->str+“-itcast”).collect(Collectors.toList());
flatMap使用flatMap方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流。List strings = Arrays.asList(“abc”, “abc”, “bc”, “efg”, “abcd”,“jkl”, “jkl”);Stream flatMap = strings.stream().flatMap(Java8StreamTest::getCharacterByString);
sorted返回排序后的流List strings1 = Arrays.asList(“abc”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);List sorted1 = strings1.stream().sorted().collect(Collectors.toList());

终止操作符

流方法含义示例
anyMatch检查是否至少匹配一个元素,返回boolean。List strings = Arrays.asList(“abc”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);boolean b = strings.stream().anyMatch(s -> s == “abc”);
allMatch检查是否匹配所有元素,返回boolean。List strings = Arrays.asList(“abc”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);boolean b = strings.stream().allMatch(s -> s == “abc”);
noneMatch检查是否没有匹配所有元素,返回boolean。List strings = Arrays.asList(“abc”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);boolean b = strings.stream().noneMatch(s -> s == “abc”);
findAny将返回当前流中的任意元素。List strings = Arrays.asList(“cv”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);Optional any = strings.stream().findAny();
findFirst返回第一个元素List strings = Arrays.asList(“cv”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);Optional first = strings.stream().findFirst();
forEach遍历流List strings = Arrays.asList(“cv”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);strings.stream().forEach(s -> out.println(s));
collect收集器,将流转换为其他形式。List strings = Arrays.asList(“cv”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);Set set = strings.stream().collect(Collectors.toSet());List list = strings.stream().collect(Collectors.toList());Map<String, String> map = strings.stream().collect(Collectors.toMap(v ->v.concat(“_name”), v1 -> v1, (v1, v2) -> v1));
reduce可以将流中元素反复结合起来,得到一个值。List strings = Arrays.asList(“cv”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);Optional reduce = strings.stream().reduce((acc,item) -> {return acc+item;});if(reduce.isPresent())out.println(reduce.get());
count返回流中元素总数。List strings = Arrays.asList(“cv”, “abd”, “aba”, “efg”, “abcd”,“jkl”, “jkl”);long count = strings.stream().count();

Stream的3个注意事项:

  1. Stream只能操作一次

  2. Stream方法返回的是新的流

  3. Stream不调用终结方法,中间的操作不会执行

Stream流的conca方法

如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat :

​ static Stream concat(Stream<? extends T> a, Stream<? extends T> b)

备注:这是一个静态方法,与 java.lang.String 当中的 concat 方法是不同的。

该方法的基本使用代码如:

@Test 
public void testContact() { 
	Stream<String> streamA = Stream.of("张三"); 
	Stream<String> streamB = Stream.of("李四"); 
	Stream<String> result = Stream.concat(streamA, streamB); 
	result.forEach(System.out::println); 

}

Stream流中的结果到集合中

​ Stream流提供 collect 方法,其参数需要一个 java.util.stream.Collector<T,A, R> 接口对象来指定收集到哪

种集合中。java.util.stream.Collectors 类提供一些方法,可以作为 Collector`接口的实例:

  • public static Collector<T, ?, List> toList() :转换为 List 集合。

  • public static Collector<T, ?, Set> toSet() :转换为 Set 集合。

Stream流中的结果到数组中

Stream提供 toArray 方法来将结果放到一个数组中,返回值类型是Object[]的:

Object[] toArray()

对流中数据进行聚合计算

​ 当我们使用Stream流处理数据后,可以像数据库的聚合函数一样对某个字段进行操作。比如获取最大值,获取最小值,求总和,平均值,统计数量。

@Test 
public void testStreamToOther() { 
Stream<Student> studentStream = Stream.of( 
	new Student("赵丽颖", 58, 95), 
	new Student("杨颖", 56, 88), 
	new Student("迪丽热巴", 56, 99), 
	new Student("柳岩", 52, 77)); 
	// 获取最大值 
	// Optional<Student> collect = studentStream.collect(Collectors.maxBy((o1, o2) -> 
	o1.getSocre() - o2.getSocre())); 
	// 获取最小值 
	// Optional<Student> collect = studentStream.collect(Collectors.minBy((o1, o2) -> 
	o1.getSocre() - o2.getSocre())); 
	// System.out.println(collect.get()); 
	// 求总和 
	// int sumAge = studentStream.collect(Collectors.summingInt(s -> s.getAge())); 
	// System.out.println("sumAge = " + sumAge); 
	// 平均值 
	// double avgScore = studentStream.collect(Collectors.averagingInt(s -> s.getSocre())); 
	// System.out.println("avgScore = " + avgScore); 
	// 统计数量 
	// Long count = studentStream.collect(Collectors.counting()); 
	// System.out.println("count = " + count); 
}

对流中数据进行分组

当我们使用Stream流处理数据后,可以根据某个属性将数据分组:

// 分组
@Test 
public void testGroup() { 
Stream<Student> studentStream = Stream.of( 
	new Student("赵丽颖", 52, 95), 
	new Student("杨颖", 56, 88), 
	new Student("迪丽热巴", 56, 55), 
	new Student("柳岩", 52, 33)); 
	// Map<Integer, List<Student>> map = 
	studentStream.collect(Collectors.groupingBy(Student::getAge)); 

  // 将分数大于60的分为一组,小于60分成另一组 
  Map<String, List<Student>> map = studentStream.collect(Collectors.groupingBy((s) ->
  { if (s.getSocre() > 60) { 
  return "及格"; 
  } else { 
	return "不及格"; 
  }})); 
  map.forEach((k, v) -> { 
  System.out.println(k + "::" + v); 
  }); 
}
多级分组
@Test
public void testCustomGroup () {
    Stream<Student> studentStream = Stream.of(
            new Student("赵丽颖", 52, 95),
            new Student("杨颖", 56, 88),
            new Student("迪丽热巴", 56, 99),
            new Student("柳岩", 52, 77));
    Map<Integer, Map<String, List<Student>>> map =
            studentStream.collect(Collectors.groupingBy(s -> s.getAge(), Collectors.groupingBy(s -> {
                if (s.getSocre() >= 90) {
                    return "优秀";
                } else if (s.getSocre() >= 80 && s.getSocre() < 90) {
                    return "良好";
                } else if (s.getSocre() >= 80 && s.getSocre() < 80) {
                    return "及格";
                } else {
                    return "不及格";
                }
            })));
    map.forEach((k, v) -> {
        System.out.println(k + " == " + v);
    });
}

分区

  // 分区
        @Test
        public void testPartition() {
            Stream<Student> studentStream = Stream.of(
                    new Student("赵丽颖", 52, 95),
                    new Student("杨颖", 56, 88),
                    new Student("迪丽热巴", 56, 99),
                    new Student("柳岩", 52, 77));
// partitioningBy会根据值是否为true,把集合分割为两个列表,一个true列表,一个false列表。
            Map<Boolean, List<Student>> map = studentStream.collect(Collectors.partitioningBy(s ->
                    s.getSocre() > 90));
            map.forEach((k, v) -> {
                System.out.println(k + " == " + v);
            });
        }

对流中数据进行拼接

Collectors.joining 会根据指定的连接符,将所有元素连接成一个字符串。

 @Test
    public void testJoining() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 99),
                new Student("柳岩", 52, 77));
        String collect = studentStream
                .map(Student::getName)
                .collect(Collectors.joining(">_<", "^_^", "^v^"));
        System.out.println(collect);
    }
}

小结

收集Stream流中的结果

  • 到集合中: Collectors.toList()/Collectors.toSet()/Collectors.toCollection()

  • 到数组中: toArray()/toArray(int[]::new)

  • 聚合计算:

    Collectors.maxBy/Collectors.minBy/Collectors.counting/Collectors.summingInt/Collectors.averagingInt

  • 分组: Collectors.groupingBy

  • 分区: Collectors.partitionBy

  • 拼接: Collectors.joinging

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值