Java8新特性
Lambda
即匿名函数.
作为函数式接口的实例,举例:
Compartor comp = (o1 , o2) -> Integer.compare(o1, o2);
上述中右边即为Lambda格式说明:
->: Lambda操作符或箭头操作符.
->左边: Lambda形参列表(其实就是接口中的抽象方法的形参列表).
->右边: Lambda体(重写的抽象方法的方法体).
代码示例:
//Lambda表达式的举例说明
@Test
public void test2(){
Comparator<Integer> comp1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(comp1.compare(21, 41));
System.out.println("============lambda==============");
Comparator<Integer> comp2 = (o1,o2)-> Integer.compare(o1,o2);
System.out.println(comp2.compare(32, 12));
System.out.println("============方法引用==============");
Comparator<Integer> comp3 =Integer::compare;
System.out.println(comp3.compare(11, 11));
}
@Test
public void test1(){
Runnable run1 = new Runnable() {
@Override
public void run() {
System.out.println("runnable");
}
};
run1.run();
System.out.println("==========lambda============");
Runnable run2 = ()->System.out.println("lambda runnable") ;
run2.run();
}
函数式接口
用@FunctionalInterface校验.
即接口中只包含一个抽象方法,可以用Lambda来创建该接口的对象(即匿名实现类都可以用Lambda表达式来写).
Java内核的4大核心函数式接口:
消费性接口 Consumer void accept(T t)
供给型接口 Supplier T get()
函数型接口 Function<T,R> R apply(T t)
断定型接口 Predicate boolean test(T t)
代码示例:
//函数式接口
@Test
public void test2(){
List<String> strings = Arrays.asList("北京", "南京", "西京", "东京", "平静");
List<String> list = filterString(strings, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("京");
}
});
System.out.println(list);
System.out.println("=======lambda==========");
System.out.println(filterString(strings, s -> s.contains("京")));
}
public List<String> filterString(List<String> list, Predicate<String> pre){
ArrayList<String> strings = new ArrayList<>();
for (String s : list) {
if (pre.test(s)){
strings.add(s);
}
}
return strings;
}
@Test
public void test1(){
paySome(500, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("花费了"+aDouble);
}
});
System.out.println("============lambda===============");
paySome(500, (aDouble)-> System.out.println("花费了"+aDouble));
}
public void paySome(double d, Consumer<Double> consumer){
consumer.accept(d);
}
方法引用
本质上就是Lambda表达式,也是函数式接口的实例.
使用格式: 类(或对象)::方法名
使用情景: 当要传递给Lambda体的操作已经有实现的方法.
分三种情况:
对象::非静态方法
类::静态方法
类::分静态方法
使用要求: 要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参和返回值类型相同(类::非静态方法除外).
代码示例:
//方法引用
@Test
public void test9(){
Function<Integer,Person> fun1 = i -> new Person(i);
System.out.println(fun1.apply(1));
System.out.println("======================");
Function<Integer,Person> fun2 = Person::new;
System.out.println(fun2.apply(2));
}
@Test
public void test8(){
Supplier<Person> sup = new Supplier<Person>() {
@Override
public Person get() {
return new Person();
}
};
System.out.println("=============================");
Supplier<Person> sup1 = () -> new Person<>();
System.out.println(sup1.get());
System.out.println("=============================");
Supplier<Person> sup2 = Person::new;
System.out.println(sup2.get());
}
//对象::非静态方法(有难度)
@Test
public void test7(){
Person<Object> person = new Person<>("昊吴", 11);
Function<Person,String> fun1=p->p.getName();
System.out.println(fun1.apply(person));
System.out.println("=========================");
Function<Person,String> fun2=Person::getName;
System.out.println(fun2.apply(person));
}
@Test
public void test6(){
BiPredicate<String,String> pre1=(s1,s2)-> s1.equals(s2);
System.out.println(pre1.test("SDFA", "SDFA"));
System.out.println("===========================");
BiPredicate<String,String> pre2 = String::equals;
System.out.println(pre2.test("sfa", "dsfa"));
}
@Test
public void test5(){
Comparator<String> comp1 =(s1,s2)->s1.compareTo(s2);
System.out.println(comp1.compare("acd", "sdd"));
System.out.println("======================");
Comparator<String> comp2 = String::compareTo;
System.out.println(comp2.compare("aaa","anc"));
}
//对象::静态方法
@Test
public void test4(){
Function<Double,Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double d) {
return Math.round(d);
}
};
System.out.println(function.apply(1.1));
System.out.println("================");
Function<Double,Long> function1 =d->Math.round(d);
System.out.println(function1.apply(2.4));
System.out.println("================");
Function<Double,Long> function2 =Math::round;
System.out.println(function2.apply(3.5));
}
@Test
public void test3(){
Comparator<Integer> comp = (o1, o2) -> Integer.compare(o1, o2);
int compare = comp.compare(1, 2);
System.out.println("compare = " + compare);
System.out.println("======================");
Comparator<Integer> comp1 =Integer::compare;
int compare1 = comp1.compare(2, 1);
System.out.println("compare1 = " + compare1);
}
//类::非静态方法
@Test
public void test2(){
Person<Object> person = new Person<>("昊吴", 22);
Supplier<String> sup = () -> person.getName();
String s = sup.get();
System.out.println("s = " + s);
System.out.println("=======================");
Supplier<String> sup1 =person::getName;
String s1 = sup1.get();
System.out.println("s1 = " + s1);
}
@Test
public void test1(){
Consumer<String> con = s -> System.out.println(s);
con.accept("绍兴");
System.out.println("===========================");
Consumer<String> con1=System.out::println;
con1.accept("shaoxin");
}
构造器引用
写法: 类名::new
和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致.抽象方法的返回值类型即为构造器所属类的类型.
代码示例:
//构造器引用
@Test
public void test10(){
BiFunction<String,Integer,Person> bifun1 = (s,i)->new Person(s,i);
System.out.println(bifun1.apply("好", 1));
System.out.println("===========================");
BiFunction<String,Integer,Person> bifun2 = Person::new;
System.out.println(bifun2.apply("s飞",21344));
}
数组引用
写法: 数组类型[]::new
可以把数组当做是一个特殊的类,则写法与构造器引用一致.
代码示例:
//数组引用
@Test
public void test11(){
Function<Integer,String[]> fun1= length -> new String[length];
System.out.println(Arrays.toString(fun1.apply(5)));
System.out.println("================");
Function<Integer, String[]> fun2 = String[]::new;
System.out.println(Arrays.toString(fun2.apply(3)));
}
Steam API
Stream关注的是对数据的运算,与CPU打交道.
Collection关注的是数据的存储,与内存打交道.
注意点:
- Stream自己不会存储元素.
- Stream不会改变源对象,相反,它们会返回一个持有结果的Stream.
- Stream操作是延迟执行的,这意味着它们会等到需要结果的时候执行.
Stream执行流程
说明:
一个中间操作链,对数据源的数据进行处理.
一旦执行终止操作,就执行中间操作链,并产生结果.
之后,不会再被使用.
实例化操作
实例代码如下:
//四种实例化方式
@Test
public void test1(){
//方式一: 通过集合
ArrayList<Person> arrayList = new ArrayList<>();
//default Stream<E> stream(): 返回一个顺序流
Stream<Person> stream = arrayList.stream();
//default Stream<E> parallelStream(): 返回一个并行流
Stream<Person> parallelStream = arrayList.parallelStream();
//方式二: 通过数组
int[] array = {1, 2, 3};
//重载形式能够处理对应的基本类型的数组
IntStream intStream = Arrays.stream(array);
//自定义类型 static <T> Stream<T> stream(T[] array):返回一个流
Person[] people = {new Person(),new Person() };
Stream<Object> personStream = Arrays.stream(people);
//方式三: 通过Stream的of()
Stream<Integer> integerStream = Stream.of(1, 22, 333);
//方式四: 创建无限流
//迭代 static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成 static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
中间操作
- 筛选与切片:
- filter(Predicate p): 过滤.
distinct(): 去重.
limit(long maxSize): 截断.
ship(long n): 跳过.
- filter(Predicate p): 过滤.
- 映射:
- map(Function f): 把每个元素都映射成新的.
flatMap(Function f): 把每个值换成一个流,再把所有流连接成一个流.
- map(Function f): 把每个元素都映射成新的.
- 排序:
- sorted(): 自然排序.
sorted(Comparator comp): 定制排序.
- sorted(): 自然排序.
实例代码如下:
//Stream的中间操作
@Test
//筛选和切片
public void test(){
List<Person> personList = Arrays.asList(new Person("昊吴", 11), new Person("虚火", 22), new Person("佯攻", 33));
System.out.println("--------------------");
//filter(Predicate p) - 接收Lambda,从流中排除某些元素
personList.stream().filter(p->p.getAge()<23).forEach(System.out::println);
System.out.println("====================");
//limit(n) -截断流,使其元素不超过给定的数量
personList.stream().limit(2).forEach(System.out::println);
System.out.println("====================");
//skip(n) -跳过元素,返回一个扔掉了前n个元素的流,若不足n个则返回空
personList.stream().skip(2).forEach(System.out::println);
System.out.println("====================");
//distinct() -筛选,通过流所生成元素的hashCode()和equals()去除重复元素
ArrayList<Person> arrayList = new ArrayList<>();
arrayList.add(new Person("士大夫",1));
arrayList.add(new Person("士大夫",1));
arrayList.add(new Person("士大夫",1));
arrayList.add(new Person("士大夫",1));
arrayList.stream().distinct().forEach(System.out::println);
}
@Test
//映射
public void test3(){
List<String> list = Arrays.asList("a", "bn", "sdf");
//map(Function f) -接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射为一个新的元素
list.stream().map(f->f.toUpperCase()).forEach(System.out::println);
List<Person> personList = Arrays.asList(new Person("昊吴1", 11), new Person("虚火", 22), new Person("佯攻", 33));
Stream<String> stream = personList.stream().map(Person::getName);
stream.filter(name->name.length()>2).forEach(System.out::println);
System.out.println("===============");
//flatMap(Function f) -接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest::fromStringToStream);
streamStream.forEach(f->{
f.forEach(System.out::println);
});
System.out.println("-------------");
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest::fromStringToStream);
characterStream.forEach(System.out::println);
}
public static Stream<Character> fromStringToStream(String s){
ArrayList<Character> arrayList = new ArrayList<>();
for (Character character : s.toCharArray()) {
arrayList.add(character);
}
return arrayList.stream();
}
@Test
//排序
public void test4(){
//sorted() -自然排序 需要实现Comparable接口
List<Integer> list = Arrays.asList(234, 43, -134, 453);
list.stream().sorted().forEach(System.out::println);
System.out.println("===========================");
//sorted(Comparator com) -定制排序
List<Person> personList = Arrays.asList(new Person("虚火gdgd", 22), new Person("虚火", 22), new Person("佯攻", 1));
personList.stream().sorted((e1,e2)->{
int compare = Integer.compare(e1.getAge(), e2.getAge());
if (compare==0)
return e1.getName().compareTo(e2.getName());
return compare;
}).forEach(System.out::println);
}
终止操作
- 匹配与查找:
- allMatch(Predicate p): 检查是否匹配所有元素.
anyMatch(Predicate p): 检查是否至少匹配一个元素.
noneMatch(Predicate p): 检查是否没有匹配所有元素.
findFirst(): 返回第一个元素.
findAny(): 返回当前流中的任意元素.
count(): 返回流中元素总数.
max(Comparator c): 返回流中的最大值.
min(Comparator c): 返回流中的最小值.
forEach(Consumer c): 内部迭代(使用Collection接口,用户去迭代,称为外部迭代).
- allMatch(Predicate p): 检查是否匹配所有元素.
- 归约:
- reduce(T iden, BinaryOperator b): 将流中元素反复结合,得到一个值,返回T.
reduce(BinaryOperator b): 同上,但返回Optional.
- reduce(T iden, BinaryOperator b): 将流中元素反复结合,得到一个值,返回T.
- 收集:
- collect(Collector c): 给元素做汇总的方法.(Collector由Collectors类提供: 常用方法为toList(), toSet(), toCollection()).
实例代码如下:
//Stream终止操作
@Test
//匹配和查找
public void test5(){
List<Person> personList = Arrays.asList(new Person("昊吴的", 11), new Person("虚火", 22), new Person("佯攻", 33));
//allMatch(Predicate p) -检查是否匹配所以元素
System.out.println(personList.stream().allMatch(r -> r.getAge() > 18));
//anyMatch(Predicate p) -检查是否至少匹配一个元素
System.out.println(personList.stream().anyMatch(r -> r.getName().length() >= 3));
//noneMatch(Predicate p) -检查是否没有匹配的元素
System.out.println(personList.stream().noneMatch(r -> r.getName().contains("昊")));
//findFirst -返回第一个元素
System.out.println(personList.stream().findFirst());
//findAny -返回当前流中的任意元素
System.out.println(personList.parallelStream().findAny());
//count -返回流中元素的个数
System.out.println(personList.stream().filter(r->r.getAge()>15).count());
//max(Comparator com) -返回流中最大值
System.out.println(personList.stream().max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
//min(Comparator com) -返回流中最小值
System.out.println(personList.stream().min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
//forEach(Consumer con) -内部迭代
personList.stream().forEach(System.out::println);
}
@Test
//归约
public void test6(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//reduce(T identity, BinaryOperator<T> accumulator) 可以将流中的元素反复结合起来,得到一个值,返回T
System.out.println(list.stream().reduce(0,Integer::sum));
//reduce(BinaryOperator<T> accumulator) 可以将流中的元素反复结合起来,得到一个值,返回Optional<T>
List<Person> personList = Arrays.asList(new Person("昊吴的", 11), new Person("虚火", 22), new Person("佯攻", 33));
System.out.println(personList.stream().map(Person::getAge).reduce(Integer::max));
}
@Test
//收集
public void test7(){
//collect(Collector c) 将流转换为其他形式.接收一个Collector接口的实现,用于Stream中元素做汇总的方法
List<Person> personList = Arrays.asList(new Person("昊吴的", 11), new Person("虚火", 22), new Person("佯攻", 33));
List<Person> list = personList.stream().filter(r -> r.getAge() > 21).collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("======================");
Set<Person> set = personList.stream().collect(Collectors.toSet());
set.forEach(System.out::println);
}
注:
Stream.of(T …t): 实例化.
Stream.iterate(): 无限流.
Optional
Optional类是一个容器类,它可以保持类型T的值,代表这个值存在,或仅仅保持null,表示值存在.避免空指针异常.
确定非空情况:
Optional.of(T t): 创建一个非空的实例.
T get(): 返回值,为空报异常.
可能为空避免空指针情况:
Optional.ofNullable(T t): t可以为null.
ofElse(T other): 如果有值返回该值,没有则返回other对象.
其他方法:
Optional.empty(): 创建一个空的Optional实例.
boolean isPresent(): 判断是否包含对象.
实例代码如下:
//Optional实例
@Test
public void test1(){
Girl girl = new Girl();
// girl=null;
//Optional.of(T t): 创建一个Optional实例,t必须非空
Optional<Girl> girl1 = Optional.of(girl);
System.out.println("girl1 = " + girl1);
//Optional.empty: 创建一个空的Optional实例
System.out.println(Optional.empty());
//Optional.ofNullable(T t): t可以为null
girl=null;
Optional<Girl> girl2 = Optional.ofNullable(girl);
System.out.println("girl2 = " + girl2);
}
@Test
//避免空指针异常
public void test2(){
//orElse(T t1):如果当前的Optional内部封装的t是非空的,则返回内部的t.
//如果内部的t是空的,则返回orElse()方法中的参数t1
Optional<Girl> girl = Optional.ofNullable(new Girl());
Girl girl1 = girl.orElse(new Girl(new Boy()));
System.out.println("girl1 = " + girl1);
Optional<Girl> girl2 = Optional.ofNullable(new Girl(new Boy("哈偶王师傅")));
System.out.println(girl2.orElse(new Girl(new Boy())));
}