stream判断数组长度大于0_JDK8新特性--学习笔记(Lambda&Stream)

a73e9f3c0641c2c72a9f861523395cab.png

让你介绍lambda表达式:介绍+语法+举例(后面不需要介绍)

lambda表达式介绍

  • lambda表达式重写了函数式接口中的唯一抽象方法。
  • 函数内部实现中以接口.方法的形式调用,只是外部传入时可以无需理会对象约束,直接传入方法的实现。

lambda表达式语法

(参数)->{方法体}
  • 参数的类型名可以省略(会在调用时候进行类型推导)
  • 如果 Lambda 表达式的主体只有一条语句,花括号{}可省略,且不需要写'return'关键字
  • 有'return'关键字,必须加花括号

lambda表达式示例-与函数式接口关系

// JDK7 匿名内部类写法,非Lambda表达式写法
new Thread(new Runnable(){// 接口名
	@Override
	public void run(){// 方法名
		System.out.println("Thread run()");
	}
}).start();
Runnable r = () -> System.out.println("hello world");
new Thread(
   () -> System.out.println("hello world")
).start();
//Thread内部仍然需要在实现中以接口.方法的形式调用
private Runnable target;
target.run()

常用用法

//排序
employees.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));
employees.sort(Comparator.comparing(Employee::getName));
//输出
stream.foreach(System.out::println)

comparator排序,对于一个容器,比如set,你想实现自定义排序规则的话怎么做

java集合框架 自定义排序规则:Collections.sort(List<T> list, Comparator<? super T> c)

TreeSet<String> mmp=newTreeSet<String>( (Object o1, Object o2) ->o1.toString().compareTo(o2.toString());

大于0表示o1大于o2,等于0表示等于,小于0表示小于

lambda表达式,每个用户有个黑名单标识位,如何用lamda表达式来实现把黑名单标识位为true的过滤出来并得出String的形式

lambda底层实现

Java 8 Lambda实现原理分析

  1. 编译器会根据Lambda表达式生成一个私有的静态函数lambda$0,在该函数中执行你的逻辑
  2. 那么怎么来调用这个lambda$0函数呢,有一个类叫metafactory,它会为Lambda表达式生成了一个内部实现类,并调用lambda$0函数
  3. 形式如下:
@FunctionalInterface
interface Print<T> {
    public void print(T x);
}
public class Lambda {   
    public static void PrintString(String s, Print<String> print) {
        print.print(s);
    }
    private static void lambda$0(String x) {
        System.out.println(x);
    }
    final class $Lambda$1 implements Print{
        @Override
        public void print(Object x) {
            lambda$0((String)x);
        }
    }
    public static void main(String[] args) {
        PrintString("test", new Lambda().new $Lambda$1());
    }
}

Stream

Stream特点

  • 链式调用,Internal的操作会返回新的stream继续操作
  • 单向流动,同一个stream不能操作两次,必须使用新的stream
  • 函数式编程,不存储任何元素,不会修改数据源
  • 延迟性,只有到终止操作的语句才会把之前的中间语句执行(所以才要单向流动)1.创

Stream步骤

1.创建Stream

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

如:

通过Collection系列集合提供的stream()方法

   List<String> list = Arrays.asList("JAVA", "J2EE", "Spring", "Hibernate");
   Stream<String> stream3 = list.stream();

通过Stream类的静态方法of()获取多个值

Stream<String> streamOfArray = Stream.of("a", "b", "c");

通过Arrays中的静态方法stream()获取数组流

String[] arr = new String[] { "a", "b", "c" };
Stream<String> streamOfArrayFull = Arrays.stream(arr);

2.中间操作

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

比较常用的是map函数,将流中的元素映射成另外的值,新的值类型可以和原来的元素的类型不同

List<Integer> l = Stream.of('a','b','c')
        .map( c -> c.hashCode())
        .collect(Collectors.toList());
System.out.println(l); //[97, 98, 99]

3.终止操作(终端操作)

一个终止操作,执行中间操作链,并产生结果 。

如sum()求和,count()计数

方法引用(了解了解)

当我们想要实现一个函数式接口的那个抽象方法,但是已经有类实现了我们想要的功能,这个时候我们就可以用方法引用来直接使用现有类的功能去实现

  • 要求实现抽象方法的参数列表和返回参数,必须与引用方法保持一致
  • 方法体中只有一句调用语句,则此时可以改写为方法引用
  • 默认传入参数为lambda表达式的参数体。只有类名::实例方法名特殊另外说明
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("This is Major Tom");

lambda表达式中的实现已有相关类帮我们实现该方法

Consumer<String> consumer = System.out::println;
consumer.accept("This is Major Tom");
  • 语法格式对象
    • 引用对象::实例方法名
    • 类名::静态方法名
    • 类名::new
    • 类名::实例方法名

当使用 类名::实例方法名 方法引用时,一定是lambda表达式所接收的第一个参数来调用实例方法,如果lambda表达式接收多个参数,其余的参数作为方法的参数传递进去,若无参则实例方法也无参即可。

当方法体内存在参数.方法名的时候,就可以使用类名::实例方法

students.sort((o1, o2) -> o1.getScore() - o2.getScore());
//会变为(当然如果无参,该形式与其他形式无异)
o1.getScore(o2)

那么如果想要用类名::实例方法,则需要

public int compareByScore(Student student){
    return this.getScore() - student.getScore();
}
students.sort(Student::compareByScore);

方法引用看不懂的话,学会将它转为lambda表达式,转lambda表达式要注意盯着的不是接口,而是抽象方法。传入参数是当前调用的类!!!

常用函数式接口

f33edf32633486c1a5312a374499f559.png

Stream

Stream定义

Stream:a sequence of element from a source that supports data processing operation.
a sequence of element: 元素,即source内的内容
source:容器,承载element,如Collection,Array,I/O
Data processing operation:map,filter等数据处理操作

操作方法

intermediate operations

中间操作会返回一个新的流,并且操作是延迟执行的(lazy),它不会修改原始的数据源,而且是由在终点操作开始的时候才真正开始执行。

filter

返回的流中只包含满足断言(predicate)的数据。

List<String>strings = Arrays.asList("abc", "", "bc","efg", "abcd","", "jkl"); 
// 获取空字符串的数量 
long count = strings.stream().filter(string -> string.isEmpty()).count();

distinct

保证输出的流中包含唯一的元素,它是通过Object.equals(Object)来检查是否包含相同的元素。

List<String> l = Stream.of("a","b","c","b").distinct().collect(Collectors.toList());
System.out.println(l); //[a, b, c]

limit

获取指定数量的流

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

map

将流中的元素映射成另外的值,新的值类型可以和原来的元素的类型不同

List<Integer> l = Stream.of('a','b','c')
        .map( c -> c.hashCode())
        .collect(Collectors.toList());
System.out.println(l); //[97, 98, 99]

flatmap

混合了map+flattern的功能,它将映射后的流的元素全部放入到一个新的流中。规定返回值为stream,然后将stream合在一起。

String[] word = new String[]{"Hello","world"};
//{{h,e,l,l,o},{w,o,r,l,d}}==>{h,e,l,l,o,w,o,r,l,d}
Arrays.stream(words).map(w->w.split("")).flatMap(Arrays::Stream);

sorted

将流中的元素按照自然排序方式进行排序,如果元素没有实现Comparable,则终点操作执行时会抛出java.lang.ClassCastException异常。sorted(Comparator<? super T> comparator)可以指定排序的方式

String[] arr = new String[]{"b_123","c+342","b#632","d_123"};
List<String> l  = Arrays.stream(arr)
        .sorted((s1,s2) -> {
            if (s1.charAt(0) == s2.charAt(0))
                return s1.substring(2).compareTo(s2.substring(2));
            else
                return s1.charAt(0) - s2.charAt(0);
        })
        .collect(Collectors.toList());
System.out.println(l); //[b_123, b#632, c+342, d_123]

terminal operations

Stream只有遇到终止操作,它的源才开始执行遍历操作,而且只会进行一次遍历,而不是每个操作都执行一次遍历。

Match

  • allMatch只有在所有的元素都满足断言时才返回true,否则flase,流为空时总是返回true
  • anyMatch只有在任意一个元素满足断言时就返回true,否则flase
  • noneMatch只有在所有的元素都不满足断言时才返回true,否则flase
public boolean 	allMatch(Predicate<? super T> predicate)
public boolean 	anyMatch(Predicate<? super T> predicate)
public boolean 	noneMatch(Predicate<? super T> predicate)

System.out.println(Stream.of(1,2,3,4,5).allMatch( i -> i > 0)); //true
System.out.println(Stream.of(1,2,3,4,5).anyMatch( i -> i > 0)); //true
System.out.println(Stream.of(1,2,3,4,5).noneMatch( i -> i > 0)); //false

count

count方法返回流中的元素的数量。它实现为

mapToLong(e -> 1L).sum();

find

findAny()用来get满足条件的特定元素(一般就剩1/0,不会用到任意取),findFirst()用来获取首个满足条件元素

  • findAny()返回任意一个元素,如果流为空,返回空的Optiona
  • findFirst()返回第一个元素,如果流为空,返回空的Optional
Arrays.stream(SwitchEnum.values()).filter(switchEnum -> switchEnum.getType() == type).findAny()
                .orElse(null);
Arrays.stream(SwitchEnum.values()).filter(switchEnum -> switchEnum.getName().equals(name)).findFirst()
                .orElse(null);

reduce

  • 第一个方法使用流中的第一个值作为初始值,后面两个方法则使用一个提供的初始值。
  • accumulator是累计逻辑,其运行流程如下

96a6384366319e90dcd3dc858795dbf9.png
pubic Optional<T> 	reduce(BinaryOperator<T> accumulator)
pubic T 	reduce(T identity, BinaryOperator<T> accumulator)
pubic <U> U 	reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
Optional<Integer> total = Stream.of(1,2,3,4,5).reduce( (x, y) -> x +y);
Integer total2 = Stream.of(1,2,3,4,5).reduce(0, (x, y) -> x +y);

forEach、forEachOrdered

  • forEach遍历流的每一个元素,执行指定的action,不保证按照容器中元素原有顺序执行尤其是在并行运算中。
  • forEachOrdered,保证按照容器中元素原有顺序执行。
Stream.of(1,2,3,4,5).forEach(System.out::println);

collect

<R,A> R 	collect(Collector<? super T,A,R> collector)
<R> R 	collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)

使用一个collector执行mutable reduction操作。辅助类Collectors提供了很多的collector,可以满足我们日常的需求,你也可以创建新的collector实现特定的需求。

理解这里需要理解Collector的原理

第二个方法提供了更底层的功能,它的逻辑类似下面的伪代码:

R result = supplier.get();
for (T element : this stream)
    accumulator.accept(result, element);
return result;

List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
                                           ArrayList::addAll);
String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
                                     StringBuilder::append)
                            .toString();

类型转换

toArray():将流中的元素放入到一个数组中。

collect(Collectors.toXXX):转换为List或MAP类型

Numeric Stream

stream中还存在着IntStream,DoubleStream..,这些Stream规定了元素的基本类型。好处:

  • 每个元素占用空间更小,Integer内存空间要比int大

常用方法

构造方法与Stream一样,操作方法也与Stream一样,特色:

可以替代一些for,和简单的数组生成

  • IntStream.range(1, 5)
  • IntStream.generate(() -> ThreadLocalRandom.current().nextInt(10)).limit(3);

引用和资料来源

Stream详细API​www.ibm.com Java Stream 详解​colobu.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值