因为项目中用到了比较多有关于 Java8 中新的东西,一开始本身只是会写,可是写起来不太顺,而后就在网上找到了一个很好的关于Java8新特性的视频,因此就进行了学习了一下,如下是本身对 lambda 表达式和 Stream API 的笔记和相应的理解。 视频地址,有兴趣的能够自行观看。java
在说 Lambda 以前,首先要说的是函数式接口。这个能够说是为了 Lambda 表达式而存在的一个东西。那么什么是函数式接口?数组
定义: 接口中只有一个抽象接口。 像 java.util.function 下的全部接口都是函数式接口。Java1.8提供@FunctionalInterface检测一个接口是不是一个函数式接口。 eg: java.util.function 包下的 Consumer 接口代码数据结构
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// jdk 1.8 接口能够有默认实现
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
复制代码
了解了什么是函数式接口后,lambda 表达式就很好理解了。app
"->" 是 lambda 表达式的符号 左侧表示函数式接口中抽象方法的参数列表,右侧表示你对这个方法的实现。 举个例子eg:ide
public class Test{
public static void main(String[] args){
Consumer consumer = x-> System.out.println(x);
consumer.accept(1);
}
}
复制代码
输出 1;函数
咱们通常对函数式接口的使用的时候,都会对其进行封装。工具
Consumer 只有一个抽象方法名为 accept,参数列表只有一个泛型t,无返回值。参数的数据类型有类决定 eg:学习
/** * @ClassName ConsumerTest * @Description 消费型接口, 消费字符串字段 打印输出 * @Author ouyangkang * @Date 2019-02-18 15:46 **/
public class ConsumerTest {
public static void main(String[] args) {
test("hello",x-> System.out.println(x));
}
public static <T> void test(T t, Consumer<T> consumer) {
consumer.accept(t);
}
}
复制代码
输出:hello 若是须要多个参数列表的话,也能够在 java.util.function 包下找到相应的函数式接口 好比 ObjLongConsumer。其余的能够自行查看ui
Supplier 只有一个抽象方法名为 get,参数列表为空,有返回值,返回值得数据类型为T。spa
/** * @ClassName SupplerTest * @Description 供给型接口 字符串拼接 * @Author ouyangkang * @Date 2019-02-18 15:53 **/
public class SupplerTest {
public static void main(String[] args) {
String hello = test("hello ", () -> "word!");
System.out.println(hello);
}
public static String test(String str,Supplier<String> supplier){
return str + supplier.get();
}
}
复制代码
输出为:hello word! 若是须要返回得数据为基本数据类型,能够在 java.util.function 包下找到相应的函数式接口 好比:getAsLong 其余的能够自行查看
Function<T, R> 只有一个抽象方法名为 apply,参数列表只有一个参数为T,有返回值,返回值的数据类型为R。
/** * @ClassName FunctionTest * @Description 函数式接口 将字符串转换成大写的 * @Author ouyangkang * @Date 2019-02-18 16:01 **/
public class FunctionTest {
public static void main(String[] args) {
String test = test("hello", x -> x.toUpperCase());
System.out.println(test);
}
public static String test(String str , Function<String,String> function){
return function.apply(str);
}
}
复制代码
输出为:HELLO 若是须要多个入参,而后又返回值的话,能够在 java.util.function 包下找到相应的函数式接口 好比 BiFunction。其余的能够自行查看
断言型又名判断型。 Predicate 只有一个抽象方法名为 test,参数列表只有一个参数为 T,有返回值,返回值类型为 boolean。
/** * @ClassName PredicateTest * @Description 断言型接口,判断字符串大小是否大于6 * @Author ouyangkang * @Date 2019-02-18 16:16 **/
public class PredicateTest {
public static void main(String[] args) {
boolean hello = test("hello", x -> x.length() > 6);
System.out.println(hello);
}
public static boolean test(String str, Predicate<String> predicate){
return predicate.test(str);
}
}
复制代码
输出为: false
Stream 做为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是彻底不一样的概念。Stream中间操做,多个中间操做能够链接起来造成一个流水线,除非流水线上触发了终止操做,不然中间不会执行任何处理!而终止操做时会一次性所有处理,称为惰性处理。要进行流操做首先要获取流。有4中方法能够获取流。
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// 经常使用获取流的方式
Stream<Integer> stream = list.stream();
}
复制代码
public static void main(String[] args) {
int[] a = new int[]{1,2,3,4};
IntStream stream = Arrays.stream(a);
}
复制代码
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
}
复制代码
public static void main(String[] args) {
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
}
复制代码
全部的对流的操做能够分为4种,分别为筛选与分片,映射,排序,终结(归约,收集)
操做有filter,distant,limit,skip。 filter : 过滤操做,方法参数为断言型接口 eg:
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.filter(x->x != 2).forEach(x-> System.out.println(x));
}
复制代码
输出:
1
3
复制代码
distinct : 去重操做,方法无参数 limit : 获取前几条数据,方法参数为long skip : 跳过前多少条数据,而后获取后面全部的。 方法参数为long
经常使用操做有 map ,flatMap。 map: 对原数据进行处理,并返回处理后的数据。 方法参数为函数型接口。 eg:
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.map(x->x*2).forEach(System.out::println);
}
复制代码
输出:
2
4
6
复制代码
flatMap : 使原来流种的原有数据一个一个整合在另外一个流中。方法参数为函数型接口,可是返回值为流。 eg:
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("f","d");
list.stream().flatMap(x->list2.stream().map(y-> x + y)).forEach(System.out::println);
}
复制代码
经常使用操做有sort天然排序,合sort参数为排序器的定制排序 天然排序eg:
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.sorted().forEach(System.out::println);
}
复制代码
输出:
1
2
3
复制代码
定制排序
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.sorted((x,y)->-Integer.compare(x,y)).forEach(System.out::println);
}
复制代码
输出:
3
2
1
复制代码
reduce : 归约 -- 能够将流中的元素反复结合起来,获得一个值。 eg:
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer reduce = list1.stream().reduce(11, (x, y) -> x + y);
System.out.println(reduce);
}
复制代码
输出 : 66
这个是很是经常使用的一个操做。 将流装换为其余形式。接收到一个Collector接口的实现,用于给Stream中的元素汇总的方法。用collect方法进行收集。方法参数为Collector。Collector能够由Collectors中的toList(),toSet(),toMap(Function(T,R) key,Function(T,R) value)等静态方法实现。
User类
@Data
@ToString
public class User {
private String name;
private Integer age;
private Integer salary;
}
复制代码
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("张三", 19, 1000),
new User("张三", 58, 2000),
new User("李四", 38, 3000),
new User("赵五", 48, 4000)
);
List<String> collect = users.stream().map(x -> x.getName()).collect(Collectors.toList());
Set<String> collect1 = users.stream().map(x -> x.getName()).collect(Collectors.toSet());
Map<Integer, String> collect2 = users.stream().collect(Collectors.toMap(x -> x.getAge(), x -> x.getName()));
System.out.println(collect);
System.out.println(collect1);
System.out.println(collect2);
}
复制代码
输出:
[张三, 张三, 李四, 赵五]
[李四, 张三, 赵五]
{48=赵五, 19=张三, 38=李四, 58=张三}
复制代码
Collectors.groupingBy()方法是 返回 Collector “由基团”上的类型的输入元件操做实现 T ,根据分类功能分组元素。这个是很是经常使用的操做。 好比你要对名字相同的进行分组。 groupingBy(Function<? super T,? extends K> classifier) eg:
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("张三", 19, 1000),
new User("张三", 58, 2000),
new User("李四", 38, 3000),
new User("赵五", 48, 4000)
);
Map<String, List<User>> collect3 = users.stream().collect(Collectors.groupingBy(x -> x.getName()));
System.out.println(collect3);
}
复制代码
输出:{李四=[User{name='李四', age=38, salary=3000}], 张三=[User{name='张三', age=19, salary=1000}, User{name='张三', age=58, salary=2000}], 赵五=[User{name='赵五', age=48, salary=4000}]}
固然还有其余的一些比较复杂的分组操做,实际代码看业务来进行实现。
java8中的lambda表达式可能一开始用的时候还不是很熟悉,可是只要熟悉了,你会发现很是的好用,并且lambda表达式结合stream API能够进行编写本身的工具类。在日常项目中能够很是的省时间,提升写代码的效率。我如今给出一个List转Map的工具类。
public class CollectionStream {
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("张三", 19, 1000),
new User("张三", 58, 2000),
new User("李四", 38, 3000),
new User("赵五", 48, 4000)
);
Map<Integer, Integer> map = listToMap(users, x -> x.getAge(), x -> x.getSalary());
System.out.println(map);
}
/** * @Author ouyangkang * @Description list 转map key不能相同 ,若是相同会报错。 方法对 源数据,key,value过滤null。 * @Date 9:27 2019/2/19 * @param source 源数据 * @param key * @param value * @return java.util.Map<K,V> **/
public static <DTO, K, V> Map<K, V> listToMap(List<DTO> source, Function<? super DTO, ? extends K> key, Function<? super DTO, ? extends V> value) {
Objects.requireNonNull(source, "source not null");
Objects.requireNonNull(key, "key not null");
Objects.requireNonNull(value, "value not null");
Map<K, V> map = source.stream()
.filter(dto -> dto != null)
.filter(dto -> key.apply(dto) != null)
.filter(dto -> value.apply(dto) != null)
.collect(Collectors.toMap(key, value));
return map;
}
}
复制代码