JAVA8新特性示例Lambda、Stream

JAVA8新特性

Lambda表达式

自我理解
  • lambda可以认为是匿名对象精简语法糖;是可以作为方法参传递的代码块;
基础语法

左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,即Lambda体
语法格式一:无参数,无返回值。

()->System.out.print1n("Hel1o Lambda!");

语法格式二:一个参数,无返回值,括号可省略。

x->system.out.printin(x);
(x)->system.out.printin(x);

语法格式三:有两个以上的参数,有返回值,Lambda体中有多条语句需加大括号。
一条语句,return和{}可省略

Comparator<Integer>com=(x,y)->{
    System.out.println("函数式接口";
    return Integer.compare(x,y);
};
//省略return和{}
Comparator<Integer> comparator01 = (x,y)-> Integer.compare(x,y);
//对象的引用
Comparator<Integer> comparator02 = Integer::compare;
  • 为何可以省略?
    JVM通过上下文推断,可推断出数据类型,即“类型推断”;

小知识点:

Comparable:内部比较器,自定义类要使用Collections.sort(list)方法进行排序,则需要实现该接口;
Comparator:外部比较器用于对那些没有实现Comparable接口或者对已经实现的Comparable中的排序规则不满意进行排序.无需改变类的结构,更加灵活。(策略模式)

  • CODE
@Test
public void test01(){
	Runnable r = () -> System.out.println("lambda,无参、无返回值!");
	r.run();
	//消费型接口
	Consumer<String> consumer = a -> System.out.println(a);
	consumer.accept("lambda,一参、无返回值!");
	System.out.println("---------------");
	//方法的引用
	Consumer<String> consumer1 = System.out::println;
	consumer.accept("lambda,一参、无返回值!方法引用!");
	//多个参数
	Comparator<Integer> comparator = (x,y)->{
		System.out.println("lambda,多条语句");
		return Integer.compare(x,y);
	};
	System.out.println(comparator.compare(1, -1));
	System.out.println("----------------");
	//一条语句,return和{}可省略
	Comparator<Integer> comparator01 = (x,y)-> Integer.compare(x,y);
	System.out.println(comparator01.compare(1, 5));
	//对象的引用
	Comparator<Integer> comparator02 = Integer::compare;
}

函数式接口-@FunctionalInterface

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。

  • 常用的函数式接口
Consumer<T> : 消费型接口
Supplier<T> :供给型接口
Function<T,R>:函数型接口
Predicate<T>:断言型接口
1、Predicate:断言型接口
// 传入的字符串是否以 .sql 结尾
Predicate<String> isEndWithSql = (s) -> s.endsWith(".sql");
// 传入的字符串非 .sql 结尾
Predicate<String> notEndWithSql = isEndWithSql.negate();

boolean test = isEndWithSql.test("test.sql");
System.out.println(test);
boolean test1 = notEndWithSql.test("test.sql");
System.out.println(test1);
// 判断集合是否为空
Predicate<List<String>> isEmptyList = List::isEmpty;

2、Function:功能型接口
// 字符串转为 Integer
Function<String,Integer> toInteger = s -> Integer.valueOf(s);
System.out.println(toInteger.apply("222"));
toInteger = Integer::valueOf;
System.out.println(toInteger.apply("222"));

Function 中的 default 方法:
andThen:在 Function 执行之后
compose:在 Function 执行之前

3、Supplier:供给型接口
Supplier<StringBuilder> sbSupplier = StringBuilder::new;
StringBuilder sb = sbSupplier.get();

4、Consumer:消费型接口

Consumer<Runnable> runnableConsumer = (run) -> new Thread(run).start();
runnableConsumer.accept(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        
    }
    System.out.println("测试一下了");
});
  • CODE
/**
 * Function测试
 */
@Test
public  void functionTest() {
    Function<Integer, Integer> f = s -> s++;
    Function<Integer, Integer> g = s -> 2;
    /**
     * 下面表示在执行F时,先执行G,并且执行F时使用G的输出当作输入。
     * 相当于以下代码:
     * Integer a = g.apply(1);
     * System.out.println(f.apply(a));
     */
    System.out.println(f.compose(g).apply(1));
    /**
     * 表示执行F的Apply后使用其返回的值当作输入再执行G的Apply;
     * 相当于以下代码
     * Integer a = f.apply(1);
     * System.out.println(g.apply(a));
     */
    System.out.println(f.andThen(g).apply(1));
    /**
     * identity方法会返回一个不进行任何处理的Function,即输出与输入相等;
     */
    System.out.println(Function.identity().apply("a"));
    }
方法引用

方法引用通过方法的名字来指向一个方法。
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

自我理解:
就是已经有方法实现了lambda的条件可以直接使用的另一种写法;
函数接口的返回值、参数列表与引用方法一致

若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method;

主要有三种语法格式:

  1. 对象::实例方法名
  2. 类::静态方法名
  3. 类::实例方法名

Stream

什么是Stream?

Stream API提供了一种高效且易于使用的处理数据的方式。
Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”

特点

①Stream自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream操作是延迟执行的。会等到需要结果的时候才执行。
④Stream只能操作一次。

Stream的操作三个步骤
一、创建stream流

一个数据源(如:集合、数组),获取一个流

@Test
	public void test01(){
		//1.创建流
		//集合:collection的集合类获得stream
		List<Integer> list = new ArrayList<>();
		Stream<Integer> stream1 = list.stream();

		//数组:Arrays静态方法Arrays.stream()
		String[] strings = new String[10];
		Stream<String> stream = Arrays.stream(strings);

		//stream静态方法
		Stream<String> stringStream = Stream.of("a", "b", "c");

		//无限流:无穷尽,没有下限
		//迭代
		Stream<Integer> stream2 = Stream.iterate(1, x -> ++x);
		stream2.limit(10).forEach(System.out::println);
		//生成
		Stream.generate(Math::random).limit(10).forEach(System.out::println);
	}
二、中间操作

一个中间操作链,对数据源的数据进行处理

①筛选与切片
1.filter----接收Lambda,从流中排除某些元素

//filter()中需要使用断言型接口(Predicate)
 List<Integer> list = Arrays.asList(1,2,3,523,21,55);
 Stream<Integer> stream3 = list.stream().filter(x -> x > 10);
 stream3.forEach(System.out::println);

2.limit----截断流,使其元素不超过给定数量

List<Integer> list = Arrays.asList(1,2,3,523,21,55);
Stream<Integer> stream3 = list.stream().limit(3);
stream3.forEach(System.out::println);

3.skip----跳过元素返回一个抛弃了前n个元素的流,若流中元素不满足n个,则返回一个空流,与limit形成互补

List<Integer> list = Arrays.asList(1,2,3,523,21,55);
Stream<Integer> stream3 = list.stream().skip(3);
stream3.forEach(System.out::println);
--------------------输出---------------------
523
21
55

4.distinct----筛选,通过流所所生成元素的hashCode()和equals()去除重复元素

List<Integer> list = Arrays.asList(1,2,3,3,2,4);
 Stream<Integer> stream3 = list.stream().distinct();
 stream3.forEach(System.out::println);
 --------------------输出---------------------
 1
 2
 3
 4

注意:自定义的实体类使用distinct去重时,一定要先重写hashCode()和equals()

②映射
1.map----接收Lambda,将元素转换为其他形式或提取信息时,接收一个函数作为参数,该函数被应用到每个元素上,并将其映射成一个新的元素

//map()里面使用函数型接口(Function)
 List<String> list = Arrays.asList("aa","bb","cc");
 Stream<String> stream3 =list.stream().map(String::toUpperCase);
 stream3.forEach(System.out::println);
 ----------------------输出-----------------------
 AA
 BB
 CC

2.flatMap----接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接一个流,即多个流转为一个流

Stream.of(new Integer[]{1,5,5},new Integer[]{5,4,8,7,10})
.flatMap(Arrays::stream)
.forEach(System.out::println);

③排序
1.sorted() 自然排序 按照Comparable的方式

List<String> list = Arrays.asList("aa","cc","bb");
Stream<String> stream3 = list.stream().sorted();
stream3.forEach(System.out::println);
---------------输出-----------
aa
bb
cc

2.sorted( Comparator com)定制排序,自定义排序

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 Stream<Integer> stream3 = list.stream().sorted(Integer::compare);
 stream3.forEach(System.out::println);
 --------------输出--------------
 1
 2
 3
 3
 6
 8
 9
三. 终止操作

一个终止操作,执行中间操作链,并产生结果
①查找与匹配
1.allMatch----检查是否匹配所有元素

//allMatch()里面的时断言型接口(Predicate)
 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 boolean b = list.stream().allMatch(x -> x > 3);
 System.out.println(b);
 ------------------输出--------------------
 false
 //因为不是所有的数都大于3

2.anyMatch----检查是否有匹配至少一个元素

//anyMatch()里面的时断言型接口(Predicate)
 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 boolean b = list.stream().anyMatch(x -> x > 3);
 System.out.println(b);
  ------------------输出--------------------
 true
 //只要有大于3的数就返回true

3.noneMatch----检查是否没有匹配的元素

//noneMatch()里面的时断言型接口(Predicate)
List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
boolean b = list.stream().noneMatch(x -> x > 3);
System.out.println(b);
 ------------------输出--------------------
 false
 //双重否定,返回false就是有匹配的元素

4.findFirst----返回第一个元素

List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
Optional<Integer> first = list.stream().findFirst();
System.out.println(first.get());
-----------------输出----------------
1

5.findAny----返回当前流中的任意一元素

List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
Optional<Integer> first = list.stream().findAny();
System.out.println(first.get());
-----------------输出----------------
1

6.count-----返回流中元素的总数

List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
long count = list.stream().count();
System.out.println(count);
-----------------输出----------------
7

7.max----返回流中最大值

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 Optional<Integer> max = list.stream().max(Integer::compareTo);
 System.out.println(max.get());
 -----------------输出----------------
9

8.min----返回流中的最小值

List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
Optional<Integer> min = list.stream().min(Integer::compareTo);
System.out.println(min.get());
 -----------------输出----------------
1

9.forEach----遍历流中的元素

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 list.stream().forEach(System.out::println);
 -----------------输出----------------
1
3....
//注意:forEach的迭代操作是由Stream API完成的称为内部迭代
//借助于iterator的方式为外部迭代

②归约
1.reduce(T identity,BinaryOperator)—可以将流中元素反复结合起来得到一个值,返回T

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
 System.out.println(reduce);
 -----------------输出----------------
 32
 //根据2元运算将所有的数加起来
 //首先以0为x,1为y,结果为1,然后1为x,取3为y,结果为4,以4为x...以此类推

2.reduce(BinaryOpreator)----可以将流中元素反复结合起来,返回Optional

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);
 Optional<Integer> reduce = list.stream().reduce((x, y) -> x + y);
 System.out.println(reduce.get());
  -----------------输出----------------
 32
 //原理同上,只是这里没有初始值,直接取1为x
 //所以ist就有可能为空,当返回的值可能为空时,结果存储在Optional容器中,避免空指针异常

③收集
collect----将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

  • collect(…)
Collectors.toList()  
Collectors.toSet()  
Collectors.toCollection(HashSet::new)
//元素总数
Collectors.counting();
//工资获取平均值
Collectors.averagingDouble(User::getSalary)
//分组
Collectors.groupingBy(User::getSalary)
//多级分组
Map<Double, Map<String, List<User>>> collect = user.stream().collect(Collectors.groupingBy(User::getSalary, Collectors.groupingBy(
                u -> {
                    if ( u.getAge() <= 12) {
                        return "青年";
                    } else if ( u.getAge() <= 32) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                }
        )));
System.out.println(collect);    
-----------------输出--------------    
{4000.0={老年=[User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}], 中年=[User{name='李四', age=32, salary=4000.0}]}, 1000.0={青年=[User{name='张三', age=12, salary=1000.0}]}}
.....
并行流和顺序流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
并行流底层是Fork/Join框架。

  • 获得并行流
    集合.parallelStream();
    stream.parallel();

  • 顺序流
    stream.sequential()

可以通过parallel()和sequential()对并行流与顺序流切换;

  • fork/join

ForkJoin的框架的基本思想是分而治之。
分而治之就是将一个复杂的计算,按照设定的阈值进行分解成多个计算,然后将各个计算结果进行汇总。
即是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。

惰性求值和及早求值

只描述Stream,最终不产生新集合的方法叫作惰性求值方法;而像count这样最终会从Stream产生值的方法叫作及早求值方法。

long count = allArtists.stream()
    .filter(artist -> {
        System.out.println(artist.getName());
            return artist.isFrom("London");
        })
    .count();
  • 如何判断一个操作是惰性求值还是及早求值?
    只需要看其返回值即可:
    如果返回值是Stream,那么就是惰性求值;如果返回值不是Stream或者是void,那么就是及早求值。
    一个Stream操作中,可以有多次惰性求值,但有且仅有一次及早求值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值