java8新特性的学习与总结

Lambda表达式

Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)


lambda表达式本质上就是一个匿名方法。比如下面的例子:

public int add(int x, int y) {
    return x + y;
}

转成Lambda表达式后是这个样子:

(int x, int y) -> x + y;

参数类型也可以省略,Java编译器会根据上下文推断出来:

(x, y) -> x + y; //返回两数之和

或者

(x, y) -> { return x + y; } //显式指明返回值

java 8 in Action这本书里面的描述:

A lambda expression can be understood as a concise representation of an anonymous function
that can be passed around: it doesn’t have a name, but it has a list of parameters, a body, a
return type, and also possibly a list of exceptions that can be thrown. That’s one big definition;

#格式:

(x, y) -> x + y;
-----------------
(x,y):参数列表
x+y  : body

小插曲
@FunctionalInterface注解
修饰函数式接口,接口中的抽象方法只有一个。

#Lambda表达式用法实例:

package LambdaUse;

/**
 * @author zhangwenlong
 * @date 2019/8/25 15:17
 */
public class LambdaUse {

    public static void main(String[] args) {

        //匿名类实现
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello world");
            }
        };
        //Lambda方式实现
        Runnable r2 = ()-> System.out.println("Hello world");

        process(r1);
        process(r2);
        process(()-> System.out.println("Hello world"));
    }
    private  static void  process(Runnable r){
        r.run();
    }
}

输出的结果:

Hello world
Hello world
Hello world

FunctionalInterface注解修饰的函数

predicate的用法

import java.applet.Applet;
import java.util.*;
import java.util.function.LongPredicate;
import java.util.function.Predicate;

/**
 * @author zhangwenlong
 * @date 2019/8/25 15:30
 */
public class PredicateTest {

    //通过名字(Predicate实现)
    private static List<Apple> filterApple(List<Apple> list, Predicate<Apple> predicate){
            List<Apple> appleList = new ArrayList<>();
            for(Apple apple : list){
                if(predicate.test(apple)){
                    appleList.add(apple);
                }
            }
            return appleList;
    }
    //通过重量(LongPredicate实现)
    private static List<Apple> filterWeight(List<Apple> list, LongPredicate predicate){
        List<Apple> appleList = new ArrayList<>();
        for(Apple apple : list){
            if(predicate.test(apple.getWeight())){
                appleList.add(apple);
            }
        }
        return appleList;
    }

    public static void main(String[] args) {

        List<Apple> list = Arrays.asList(new Apple("苹果",120),new Apple("香蕉",110));
        List<Apple> applelist = filterApple(list,apple -> apple.getName().equals("苹果"));
        System.out.println(applelist);
        List<Apple> appleList = filterWeight(list, (x) -> x > 110);
        System.out.println(appleList);
    }
}


执行结果:

[Apple{name='苹果', weight=120}]
[Apple{name='苹果', weight=120}]

Lambda表达式的方法推导(3种方法)

package LambdaUse;

import java.util.function.Consumer;

/**
 * @author zhangwenlong
 * @date 2019/8/25 16:02
 */
public class MethodReference {

    private static <T> void useConsumer(Consumer<T> consumer,T t){
        consumer.accept(t);
    }

    public static void main(String[] args) {
        //定义一个匿名类
        Consumer<String> stringConsumer = (s) -> System.out.println(s);
        useConsumer(stringConsumer,"Hello World");
        //lambda
        useConsumer((s) -> System.out.println(s),"ni hao");
        //Lambda的方法推导
        useConsumer(System.out::println,"da jia hao");
    }
}

执行结果:

Hello World
ni hao
da jia hao

参数推导其他例子:

/**
 * @author zhangwenlong
 * @date 2019/8/25 16:53
 */
public class paramterMethod {

    public static void main(String[] args) {
        //情况1:A method reference to a static method (for example, the method parseInt of Integer, written Integer::parseInt)
        //静态方法
        //常用的使用
        Integer value = Integer.parseInt("123");
        System.out.println(value);
        //使用方法推导
        Function<String,Integer> stringIntegerFunction = Integer::parseInt;
        Integer apply = stringIntegerFunction.apply("123");
        System.out.println(apply);
        //情况2:A method reference to an instance method of an arbitrary type (for example, the method length of a String, written String::length)
        //对象的方法
        String ss = "helloWorld";
        System.out.println(ss.charAt(3));
        //推导方法
        BiFunction<String,Integer,Character> stringIntegerCharacterBiFunction = String::charAt;
        System.out.println(stringIntegerCharacterBiFunction.apply(ss,3));

        //情况3:构造函数方法推导
        //常用方式
        Apple apple = new Apple("苹果",120);
        System.out.println(apple);
        //推导方式
        BiFunction<String,Integer,Apple> appleBiFunction = Apple::new;
        System.out.println(appleBiFunction.apply("苹果",120));
    }
}

执行结果:

123
123
l
l
Apple{name='苹果', weight=120}
Apple{name='苹果', weight=120}

具体的详细解释可以参考:

方法推导详解

Stream(流以及一些常用的方法)
特点:并行处理
例子:

package StreamUse;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhangwenlong
 * @date 2019/8/25 17:20
 */
public class StreamTest {

    public static void main(String[] args) {
        List<Apple> appleList = Arrays.asList(
                new Apple("苹果",110),
                new Apple("桃子",120),
                new Apple("荔枝",130),
                new Apple("香蕉",140),
                new Apple("火龙果",150),
                new Apple("芒果",160)
        );
        System.out.println(getNamesByCollection(appleList));
        System.out.println(getNamesByStream(appleList));
    }

    //collection实现查询重量小于140的水果的名称
    private static List<String> getNamesByCollection(List<Apple> appleList){
        List<Apple> apples = new ArrayList<>();

        //查询重量小于140的水果
        for(Apple apple : appleList){
            if(apple.getWeight() < 140){
               apples.add(apple);
            }
        }
        //排序
        Collections.sort(apples,(a,b)->Integer.compare(a.getWeight(),b.getWeight()));

        List<String> appleNamesList = new ArrayList<>();
        for(Apple apple : apples){
            appleNamesList.add(apple.getName());
        }
        return  appleNamesList;
    }

    //stream实现查询重量小于140的水果的名称
    private static List<String> getNamesByStream(List<Apple> appleList){
        return  appleList.stream().filter(d ->d.getWeight() < 140)
                .sorted(Comparator.comparing(Apple::getWeight))
                .map(Apple::getName)
                .collect(Collectors.toList());
    }
}

流的一些常见的用法


流的特点:
1.只能遍历一次
我们可以把流想象成一条流水线,流水线的源头是我们的数据源(一个集合),数据源中的元素依次被输送到流水线上,我们可以在流水线上对元素进行各种操作。一旦元素走到了流水线的另一头,那么这些元素就被“消费掉了”,我们无法再对这个流进行操作。当然,我们可以从数据源那里再获得一个新的流重新遍历一遍。

2.采用内部迭代方式
若要对集合进行处理,则需我们手写处理代码,这就叫做外部迭代。而要对流进行处理,我们只需告诉流我们需要什么结果,处理过程由流自行完成,这就称为内部迭代。


流的数据源:
1.集合(这种数据源较为常用,通过stream()方法即可获取流对象)

List<Person> list = new ArrayList<Person>(); 
Stream<Person> stream = list.stream();

2.数组(通过Arrays类提供的静态函数stream()获取数组的流对象)

String[] names = {"chaimm","peter","john"};
Stream<String> stream = Arrays.stream(names);

3.值

Stream<String> stream = Stream.of("chaimm","peter","john");

4.文件

try(Stream lines = Files.lines(Paths.get(“文件路径名”),Charset.defaultCharset())){

    //*****可对lines做一些操作******* 
    
}catch(IOException e){ 
} 

Stream操作的三个步骤

1. 创建 Stream
一个数据源(如:集合、数组),获取一个流
2. 中间操作
一个中间操作链,对数据源的数据进行处理
3. 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用

1.创建stream
参考数据源的操作
2.中间操作
a.筛选与切片
1.filter(Predicate p)
接收Lambda,从流中排出某些元素
2.distinct()
筛选,通过流所生成元素的hashCode()和equals()去重重复元素
3.limit(long maxSize)
截断流,使其元素不超过给定的数量
4.skip(long n)
跳过元素,返回一个去掉了前n个元素的流。
b.映射
1.map(Function f)
接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
2.mapToDouble(ToDoubleFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
3.mapToInt(ToIntFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
4.mapToLong(ToLongFunction f)
接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
5.faltMap(Function f)
接收一个函数作为参数,将流中的每个值都换成另外一个流,然后把所有的流连接成一个流
c.排序
1.sorted()
产生一个新流,其中按自然顺序排序
2.sorted(Comparator comparator)
产生一个新流,其中按比较器顺序排序
3.终止操作
a.匹配与查找
1.allMatch
检查是否匹配所有元素
2.anyMatch(Predicate p)
检查是否至少匹配一个元素
3.noneMatch(Predicate p)
检查是否没有匹配所有元素
4.findFirst()
返回第一个元素
5.findAny()
返回当前流中的任意元素
b.计算与遍历
1.count()
返回流中元素总数
2.max(Comparator c)
返回流中最大值
3.min(Comparator c)
返回流中最小值
4.forEach(Consumer c)
内部迭代(可以传入Lambda实现特定的遍历与操作)
c.归约
1.reduce(T iden, BinaryOperator b)
可以将流中的元素反复结合起来,得到一个值,返回T
2.reduce(BinaryOperator b)
可以将流中的元素反复结合起来,得到一个值,返回Optional
d.收集
collect(Collector c)
将流转换成其他形式,接收一个Collector接口的实现,用于给Stream中的元素做汇总的方法
1.toList
2.toSet
3.toCollection


常用1:filter/distinct/skip/limit/map/flatmap

例子:

package StreamUse;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhangwenlong
 * @date 2019/8/25 21:03
 */
public class StreamTest2 {

    public static void main(String[] args) {

        List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,6,7,8);
        /*
         * 1.从第3个数字开始查询
         * 2.获取大于5的数字
         * 3.去掉重复的数字
         * 4.获取列表满足条件的前2个数据
         */
        //1.从第3个数字开始查询(skip)
        integerList.stream()
                .skip(2)
                .collect(Collectors.toList())
                .forEach(System.out::print);
        System.out.println();
        //获取大于5的数字(filter)
        integerList.stream()
                .skip(2)
                .filter(x->x > 5)
                .collect(Collectors.toList())
                .forEach(System.out::print);
        System.out.println();
        //去掉重复的数字(distinct)
        integerList.stream()
                .distinct()
                .skip(2)
                .filter(x->x > 5)
                .collect(Collectors.toList())
                .forEach(System.out::print);
        System.out.println();
        //4.获取列表满足条件的前2个数据(limit)
        integerList.stream()
                .distinct()
                .skip(2)
                .filter(x->x > 5)
                .limit(2)
                .collect(Collectors.toList())
                .forEach(System.out::print);
        System.out.println();

        List<Apple> appleList = Arrays.asList(
                new Apple("苹果",110),
                new Apple("桃子",120),
                new Apple("荔枝",130),
                new Apple("香蕉",140),
                new Apple("火龙果",150),
                new Apple("芒果",160),
                new Apple("芒果",160),
                new Apple("梨子",170)
        );

        //获取重量小于150的水果的名字(map)
        List<String> stringList = appleList.stream()
                .filter(w -> w.getWeight() < 150)
                .map(Apple::getName)
                .collect(Collectors.toList());
        System.out.println(stringList);
    }
}

执行结果:

3456678
6678
678
67
[苹果, 桃子, 荔枝, 香蕉]

flatmap和map的差异

map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗;

flatMap:和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中;

例子:

package StreamUse;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhangwenlong
 * @date 2019/8/25 21:55
 */
public class flatMaPTest {

    public static void main(String[] args) {
        List<String> words = Arrays.asList("hello","world");

        //将words数组中的元素再按照字符拆分,然后字符去重,最终达到["h", "e", "l", "o", "w", "r", "d"]
        //如果使用map,是达不到直接转化成List<String>的结果
        List<String> stringList = words.stream()
                .flatMap(word -> Arrays.stream(word.split("")))
                .collect(Collectors.toList());
        stringList.forEach(e -> System.out.print(e));
        System.out.println();
        //map
        List<String[]> collect = words.stream()
                .map(word -> word.split(""))
                .collect(Collectors.toList());
        collect.forEach(str->{
            for(String a : Arrays.asList(str)){
                System.out.print(a);
            }
            System.out.println();
        });
    }
}

执行结果:

helloworld
hello
world

常用2:match/find/reduce

match使用

package StreamUse;

import java.util.Arrays;
import java.util.List;

/**
 * @author zhangwenlong
 * @date 2019/8/25 22:23
 */
public class matchTest {

    public static void main(String[] args) {
        List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,6,7);
        //检测当前列表所有元素是否都大于0
        boolean b1 = integerList.stream().allMatch(x -> x > 0);
        System.out.println(b1);
        //检测当前列表所有元素是否都大于10
        boolean b2 = integerList.stream().allMatch(x -> x > 10);
        System.out.println(b2);
        //检查当前列表有元素大于6
        boolean b3 = integerList.stream().anyMatch(x -> x > 6);
        System.out.println(b3);
        //检查当前列表元素都不小于0
        boolean b4 = integerList.stream().noneMatch(x -> x < 0);
        System.out.println(b3);
    }
}

执行结果:

true
false
true
true

find的使用

package StreamUse;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author zhangwenlong
 * @date 2019/8/25 22:32
 */
public class findTest {

    public static void main(String[] args) {
        List<Integer> integerList = Arrays.asList(1,2,3,4,5,6,6,7);
        Optional<Integer> optional1 = integerList.stream().filter(a -> a % 2 == 0).findAny();
        System.out.println(optional1.get());
        Optional<Integer> optional2 = integerList.stream().filter(a -> a % 2 == 0).findFirst();
        System.out.println(optional2.get());
    }
}

执行结果:

2
2

reduce的使用

例子:

package StreamUse;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author zhangwenlong
 * @date 2019/8/28 21:34
 */
public class TestStreamAPI2 {

    /**
     * 归约
     * 1、reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回 T
     * 2、reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
     */
    public static void main(String[] args) {
        List<Person> person = Arrays.asList(
                new Person("李四", 59, 1111.22),
                new Person("张三", 18, 2222.33),
                new Person("王五", 28, 3333.11),
                new Person("赵六", 8, 4444.66)
        );

        // reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回 T
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //先把0作为了x,y是流中的第一个元素 相加得1,然后1作为x,流中的第二个元素作为y,就这样,依次加下去。
        Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(reduce);
        System.out.println("*******************************************");

        // reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
        //可以看出两个reduce方法返回的并不一样,因为第一个reduce方法有初始值,最后所得的值肯定不会为空,而第二种情况则有可能会为空,所以返回值为optional
        Optional<Double> reduce2 = person.stream().map(Person::getSalary)
                .reduce(Double::sum);
        System.out.println(reduce2);
    }
}

执行结果:

55
*******************************************
Optional[11111.32]

Optional的用法

用于简化Java中对空值的判断处理,以防止出现各种空指针异常。 
Optional实际上是对一个变量进行封装,它包含有一个属性value,实际上就是这个变量的值。

1.Optional对象创建
它的构造函数都是private类型的,因此要初始化一个Optional的对象无法通过其构造函数进行创建。 它提供了一系列的静态方法用于构建Optional对象:

2.empty
用于创建一个空的Optional对象;其value属性为Null。如:

Optional o = Optional.empty();

3.of
根据传入的值构建一个Optional对象;
传入的值必须是非空值,否则如果传入的值为空值,则会抛出空指针异常。
使用:

o = Optional.of("test"); 

4. ofNullable
根据传入值构建一个Optional对象
传入的值可以是空值,如果传入的值是空值,则与empty返回的结果是一样的。

Optional方法
Optional包含以下方法:
get
获取Value的值,如果Value值是空值,则会抛出NoSuchElementException异常;因此返回的Value值无需再做空值判断,只要没有抛出异常,都会是非空值。
isPresent Value是否为空值的判断;
ifPresent 当Value不为空时,执行传入的Consumer;
ifPresentOrElse Value不为空时,执行传入的Consumer;否则执行传入的Runnable对象;
filter
当Value为空或者传入的Predicate对象调用test(value)返回False时,返回Empty对象;否则返回当前的Optional对象
map
一对一转换:当Value为空时返回Empty对象,否则返回传入的Function执行apply(value)后的结果组装的Optional对象;
flatMap
一对多转换:当Value为空时返回Empty对象,否则传入的Function执行apply(value)后返回的结果(其返回结果直接是Optional对象)
or
如果Value不为空,则返回当前的Optional对象;否则,返回传入的Supplier生成的Optional对象
stream 如果Value为空,返回Stream对象的Empty值;否则返回Stream.of(value)的Stream对象
orElse Value不为空则返回Value,否则返回传入的值;
orElseGet Value不为空则返回Value,否则返回传入的Supplier生成的值;
orElseThrow Value不为空则返回Value,否则抛出Supplier中生成的异常对象;
使用场景
常用的使用场景如下:

1 判断结果不为空后使用
如某个函数可能会返回空值,以往的做法:

String s = test();
if (null != s) {
    System.out.println(s);
}

现在的写法就可以是:

Optional<String> s = Optional.ofNullable(test());
s.ifPresent(System.out::println)

2 变量为空时提供默认值
如要判断某个变量为空时使用提供的值,然后再针对这个变量做某种运算;
以往做法:

if (null == s) {
    s = "test";
}
System.out.println(s);

现在的做法:

Optional<String> o = Optional.ofNullable(s);
System.out.println(o.orElse("test"));

3 变量为空时抛出异常,否则使用
以往的写法:

if (null == s) {
    throw new Exception("test");
}
System.out.println(s);

现在的写法:

Optional<String> o = Optional.ofNullable(s);
System.out.println(o.orElseThrow(()->new Exception("test")));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值