码迷,mamicode.com
首页 > 编程语言 > 详细

java8新特性-Lambda表达式(二)

时间:2019-12-12 13:11:24      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:匿名内部类   string   数据   线程   cas   base   tor   mamicode   bic   

Java8新增了java.util.funcion包,里面包含常用的函数接口,这是Lambda表达式的基础,Java集合框架也新增部分接口,以便与Lambda表达式对接。

Collections中的常用函数接口

Java集合框架的接口继承结构:

技术图片

 

 

 上图中蓝色标记和橙色标记的接口类,表示在Java8中加入了新的接口方法,由于继承关系,他们相应的子类也会继承这些方法。

下面用一张表列举这些方法

接口名 Java8新加入的方法
Collection removeIf() spliterator() stream() parallelStream() forEach()
List replaceAll() sort()
Map getOrDefault() forEach() replaceAll() putIfAbsent() replace() computeIfAbsent() computeIfPresent() compute() merge

这些新加入的方法大部分要用到java.util.function包下的接口,这就表明这些方法大部分都和Lambda表达式相关

Collections中的新方法

forEach()

该方法名为void forEach(Consumer action),作用是对容器中的每个元素执行action指定的动作,其中Consumer是个函数接口,里面只有一个待实现方法void accept(T t)

匿名内部类实现:

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3,6,9,10));
        list.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                if (integer%3==0){
                    System.out.println(integer);
                }
            }
        });

Lambda表达式实现:

//Lambda表达式实现
list.forEach(s->{
     if (s%3==0){
           System.out.println(s);
      }
});         

运行结果都是 :

技术图片

 

 removeIf()

该方法签名为boolean removeIf(Predicate filter),作用是删除容器中所有满足filter指定条件的元素,其中Predicate是一个函数接口,里面只有一个待实现方法boolean test(T t)。

匿名内部类以及Lambda表达式实现:

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3,6,9,10));
//匿名内部类实现
list.removeIf(new Predicate<Integer>() {
    @Override
    public boolean test(Integer integer) {

        return integer%3==0;
    }
});
System.out.println(list);

//Lambda表达式实现
list.removeIf(s->s%3==0);
System.out.println(list);

运行结果:

技术图片

replaceAll()

该方法签名为void replaceAll(UnaryOperator<E> operator),作用是对每个元素执行operator指定的操作,并用操作结果来替换原来的元素。其中UnaryOperator是一个函数接口,里面只有一个待实现函数T apply(T t)。

匿名内部类以及Lambda表达式实现:

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(3,6,9,10));
//匿名内部类实现
list.replaceAll(new UnaryOperator<Integer>() {
    @Override
    public Integer apply(Integer integer) {
        if(integer%3==0){
            return ++integer;
        }
        return --integer;
    }
});
System.out.println(list);

//Lambda表达式实现
list.replaceAll(s->{
    if(s%3==0){
      return ++s;
    }
    return --s;
});
System.out.println(list);

运行结果:

技术图片

sort()

该方法定义在List接口中,方法签名为void sort(Comparator c),该方法根据c指定的比较规则对容器元素进行排序。Comparator接口中有一个方法int compare(T o1, T o2)需要实现,该接口是个函数接口。

匿名内部类以及Lambda表达式实现:

ArrayList<Integer> list = new ArrayList<>(Arrays.asList(10,9,6,3));
//匿名内部类实现
Collections.sort(list, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1-o2;
    }
});
System.out.println(list);

//Lambda表达式实现
Collections.sort(list,(first,second)->first-second);
System.out.println(list);

运行结果:

技术图片

spliterator()

方法签名为Spliterator<E> spliterator(),该方法返回容器的可拆分迭代器。从名字来看该方法跟iterator()方法有点像,我们知道Iterator是用来迭代容器的,Spliterator也有类似作用,但二者有如下不同:

Spliterator既可以像Iterator那样逐个迭代,也可以批量迭代。批量迭代可以降低迭代的开销。

Spliterator是可拆分的,一个Spliterator可以通过调用Spliterator trySplit()方法来尝试分成两个。一个是this,另一个是新返回的那个,这两个迭代器代表的元素没有重叠。
可通过(多次)调用Spliterator.trySplit()方法来分解负载,以便多线程处理。

stream()和parallelStream()

stream()和parallelStream()分别返回该容器的Stream视图表示,不同之处在于parallelStream()返回并行的Stream。Stream是Java函数式编程的核心类,具体内容后面单独介绍。

Map中的新方法

forEach()

该方法签名为void forEach(BiConsumer action),作用是对Map中的每个映射执行action指定的操作,其中BiConsumer是一个函数接口,里面有一个待实现方法void accept(T t, U u)。

Map<Integer,String> map = new HashMap<>();
map.put(1,"我");
map.put(2,"拒绝");
map.put(3,"996");
//匿名内部类实现
map.forEach(new BiConsumer<Integer, String>() {
    @Override
    public void accept(Integer integer, String s) {
        System.out.println(integer+"="+s);
    }
});

//Lambda表达式实现
map.forEach((key,value)-> System.out.println(key+"="+value));

运行结果:

技术图片

该方法跟Lambda表达式虽然没关系,但是很有用。

方法签名为V getOrDefault(Object key, V defaultValue),作用是按照给定的key查询Map中对应的value,如果没有找到则返回defaultValue。使用该方法可以省去查询指定键值是否存在的麻烦。

匿名内部类实现方式以及Lambda表达式实现方式:

//Java7以前的做法
if (map.containsKey(4)) {
    System.out.println(map.get(4));
} else {
    System.out.println("noValue");
}
//Java8使用Map.getOrDefault()
System.out.println(map.getOrDefault(4,"noValue"));

运行结果:

技术图片

 

putIfAbsent()

 

该方法跟Lambda表达式没关系,但是很有用。方法签名为V putIfAbsent(K key, V value),作用是只有在不存在key值的映射或映射值为null时,才将value指定的值放入到Map中,否则不对Map做更改.该方法将条件判断和赋值合二为一,使用起来更加方便。

 

remove()

 

我们都知道Map中有一个remove(Object key)方法,来根据指定key值删除Map中的映射关系;Java8新增了remove(Object key, Object value)方法,只有在当前Map中key正好映射到value时才删除该映射,否则什么也不做。

 

replace()

 

在Java7及以前,要想替换Map中的映射关系可通过put(K key, V value)方法实现,该方法总是会用新值替换原来的值.为了更精确的控制替换行为,Java8在Map中加入了两个replace()方法,分别如下:

 

  • replace(K key, V value),只有在当前Map中key的映射存在时才用value去替换原来的值,否则什么也不做。

  • replace(K key, V oldValue, V newValue),只有在当前Map中key的映射存在且等于oldValue时才用newValue去替换原来的值,否则什么也不做。

 

replaceAll()

该方法签名为replaceAll(BiFunction function),作用是对Map中的每个映射执行function指定的操作,并用function的执行结果替换原来的value,其中BiFunction是一个函数接口,里面有一个待实现方法R apply(T t, U u)。

匿名内部类实现方式以及Lambda表达式实现方式:

 

Map<Integer,String> map = new HashMap<>();
map.put(1,"我");
map.put(2,"拒绝");
map.put(3,"996");
//匿名内部类实现方式
map.replaceAll(new BiFunction<Integer, String, String>() {
    @Override
    public String apply(Integer integer, String s) {
        if(s.equals("我")){
            s = "他";
        }
        return s.toUpperCase();
    }
});
map.forEach((key,value)-> System.out.println(key+"="+value));
//Lambda表达式实现方式
map.replaceAll((key,value)->{
    if (value.equals("拒绝")) {
        value = "Like";
    }
    return value.toUpperCase();
});
map.forEach((key,value)-> System.out.println(key+"="+value));

 

运行结果:

技术图片

 

 

merge()

 

该方法签名为merge(K key, V value, BiFunction remappingFunction)。

 

作用是:

 

  • 如果Map中key对应的映射不存在或者为null,则将value(不能是null)关联到key上;

  • 否则执行remappingFunction,如果执行结果非null则用该结果跟key关联,否则在Map中删除key的映射。

    参数中BiFunction函数接口前面已经介绍过,里面有一个待实现方法R apply(T t, U u)。

 

merge()方法虽然语义有些复杂,但该方法的用方式很明确,一个比较常见的场景是将新的错误信息拼接到原来的信息上,比如:

 

 

Map<Integer,String> map = new HashMap<>();
map.put(1,"我");
map.put(2,"拒绝");
map.put(3,"996");
map.forEach((key, value) -> System.out.println(key + "=" + value));
map.merge(1, "和你", (v1, v2) -> v1+v2);
map.forEach((key, value) -> System.out.println(key + "=" + value));

 

运行结果:

技术图片

 

 

compute()

 

该方法签名为compute(K key, BiFunction remappingFunction),作用是把remappingFunction的计算结果关联到key上,如果计算结果为null,则在Map中删除key的映射。

 

 

Map<Integer,String> map = new HashMap<>();
map.put(1,"我");
map.put(2,"拒绝");
map.put(3,"996");
map.forEach((key, value) -> System.out.println(key + "=" + value));
//计算结果不是null
System.out.println("---------------------------");
map.compute(1, (k,v) -> v == null ? "值为空" : v.concat("和你"));
map.forEach((key, value) -> System.out.println(key + "=" + value));
//计算结果为null
System.out.println("---------------------------");
map.compute(4, (k,v) -> v == null ? "值为空" : v.concat("和你"));
map.forEach((key, value) -> System.out.println(key + "=" + value));

 

运行结果:

技术图片

computeIfAbsent()

该方法签名为V computeIfAbsent(K key, Function mappingFunction)

作用是:只有在当前Map中不存在key值的映射或映射值为null时,才调用mappingFunction,并在mappingFunction执行结果非null时,将结果跟key关联。

Function是一个函数接口,里面有一个待实现方法R apply(T t)。

computeIfAbsent()常用来对Map的某个key值建立初始化映射.比如我们要实现一个多值映射,Map的定义可能是Map<K,Set<V>>,要向Map中放入新值,可通过如下代码实现:

Map<Integer, Set<String>> map = new HashMap<>();
// Java7及以前的实现方式
if(map.containsKey(1)){
    map.get(1).add("123");
}else{
    Set<String> valueSet = new HashSet<String>();
    valueSet.add("123");
    map.put(1, valueSet);
}
// Java8的实现方式
map.computeIfAbsent(1, v -> new HashSet<String>()).add("345");
map.forEach((key, value) -> System.out.println(key + "=" + value));

 

运行结果:

技术图片

 

 

使用computeIfAbsent()将条件判断和添加操作合二为一,使代码更加简洁。

 

computeIfPresent()

 

该方法签名为V computeIfPresent(K key, BiFunction remappingFunction),作用跟computeIfAbsent()相反。即只有在当前Map中存在key值的映射且非null时,才调用remappingFunction,如果remappingFunction执行结果为null,则删除key的映射,否则使用该结果替换key原来的映射。

 

Stream

对于Java 7来说stream完全是个陌生东西,stream并不是某种数据结构,它只是数据源的一种视图。这里的数据源可以是一个数组,Java容器或I/O channel等。

常见的stream接口继承关系如下:

BaseStream(IntStream,LongStream,DoubleSream,Stream)

其中IntStream、LongStream、DoubleStream对应三种基本类型(int,Long,Double)注意:是基本类型不是包装类型

Stream接口部分常见方法

操作类型 操作方法
中间操作 concat() distinct() filter() limit() map() peek() skip() sorted() parallel() sequential() unordered()
结束操作 allMatch() anyMatch() collect() count() findAny() findFirst() forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()

java8新特性-Lambda表达式(二)

标签:匿名内部类   string   数据   线程   cas   base   tor   mamicode   bic   

原文地址:https://www.cnblogs.com/yanglanwan/p/12028405.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!