【技术积累】Java 8 新特性

这篇具有很好参考价值的文章主要介绍了【技术积累】Java 8 新特性。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Lambda表达式

Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升

1、举例

( o1 , o2 ) -> Integer.compare( o1 , o2 )

2、格式

  • -> : lambda 操作符或箭头操作符
  • -> 左边 :lambda 形参列表(其实就是抽象中的抽象方法的形参列表)
  • -> 右边 :lambda 体(其实就是重写的抽象方法的方法体)

3、lambda 表达式的使用(6种情况)

        Runnable r = () -> System.out.println("hello");
        Consumer<String> consumer =  (args) -> System.out.println(args);
        Consumer<String> consumer2 =  args -> System.out.println(args);
    	BinaryOperator<Long> bo = (Long x,Long y) -> {
            System.out.println("实现函数接口方法!");
            return x + y;
        };
        BinaryOperator<Long> bio = (Long x,Long y) -> x + y;
        BinaryOperator<Long> bio = (x, y) -> x + y;

4、lambda 表达式的本质:作为接口的实例

二、函数式接口

1、什么是函数式接口

  • 只包含一个抽象方法的接口,称为函数式接口。
  • 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
  • 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。

image.png

2、自定义函数式接口

@FunctionalInterface
public interface MyInterface {
    public String getValue();
}

@FunctionalInterface
public interface MyInterface<T> {
    public T getValue(T t);
}

3、Lambda 表达式作为参数传递

注意:为了将 Lambda 表达式作为参数传递,接收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。
image.png

4、Java 内置四大核心函数式接口

image.png

消费型接口Consumer void accept(T t)

	@Test
    public void testConsumer() {
        // 消费型接口Consumer<T>        void accept(T t)
        buyCar(265000.00, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("买车花费了:" + aDouble);
            }
        });
        System.out.println("使用lambda表达式如下");
        buyCar(99999.99, money -> System.out.println("买车花费了:" + money));
    }

	/**
     * 利用Consumer 实现消费
     * @param money 金额
     * @param con 所消费金额
     */
    public void buyCar(Double money, Consumer<Double> con) {
        con.accept(money);
    }

image.png

断定型接口Predicate boolean test(T t)

	@Test
    public void testPredicate() {
        // 断定型接口Predicate<T>       boolean test(T t)
        List<String> list = Arrays.asList("aabb", "bbcc", "ccdd", "aadd");
        List<String> res = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("aa");
            }
        });
        System.out.println("过滤后:" + res);
        System.out.println("使用lambda表达式如下");
        List<String> res2 = filterString(list, s -> s.contains("aa"));
        System.out.println("过滤后:" + res2);

    }

    /**
     * 利用Predicate 实现过滤
     * @param list 原数组
     * @param pre 约束条件
     * @return 过滤后数组
     */
    public List<String> filterString(List<String> list, Predicate<String> pre) {
        List<String> result = new ArrayList<>();

        for (String s : list) {
            if (pre.test(s)) {
                result.add(s);
            }
        }
        return result;
    }

image.png供给型接口Supplier T get()

函数型接口Function<T,R> R apply(T t)

5、其他接口

image.png

三、函数式引用(方法引用与构造器引用)

使用场景

当要传递给 Lambda 体的操作,已经有实现的方法了,可以使用方法引用!
方法引用,本质上也是 Lambda 表达式,而 Lambda 表达式作为函数式接口的实例。所以,方法引用也是函数式接口的实例。

使用格式

方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(情况三特殊)
情况一 对象 :: 非静态方法
情况二 类 :: 静态方法
情况三 类 :: 非静态方法

示例代码

package com.mv.java8.basic;

import org.junit.Test;

import java.io.PrintStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
* 方法引用
* 1.使用情景:当要传递给 Lambda 体的操作,已经有实现的方法了,可以使用方法引用!
* 2.方法引用,本质上也是 Lambda 表达式,而 Lambda 表达式作为函数式接口的实例。所以,方法引用也是函数式接口的实例。
* 3.使用格式: 类 (或对象) :: 方法名
* 4.具体分为以下三种情况
* 5.方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!
* 对象 :: 非静态方法
* 类 :: 静态方法
* 类 :: 非静态方法
*
* @author wv
* @version V1.0
* @date 2023/8/3 19:45
*/
public class MethodRefTest {


    @Test
    public void test01() {

        // 情况一 : 对象 :: 实例方法
        // Consumer 中的 void accept(T t)
        // PrintStream 中的 void println(T t)

        Consumer<String> con1 = str -> System.out.println(str);
        con1.accept("hello");

        System.out.println("使用方法引用如下:");

        //        PrintStream printStream = System.out;
        //        Consumer<String> con2 = printStream::println;
        Consumer<String> con2 = System.out::println;
        con2.accept("world");

    }

    @Test
    public void test02() {

        // 情况二 : 类 :: 静态方法
        // Comparator 中的 int compare(T t1, T t2)
        // Integer 中的 int compare(T t1, T t2)

        Comparator<Integer> com1 = (a, b) -> Integer.compare(a, b);
        System.out.println(com1.compare(10, 5));

        System.out.println("使用方法引用如下:");
        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com1.compare(5, 10));

        // Function 中的 apply(T t)
        // Math 中的 Long round(Double d)
        Function<Double, Long> func = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        System.out.println(func.apply(3.14));
        System.out.println("使用方法引用如下:");
        Function<Double, Long> func1 = Math::round;
        System.out.println(func1.apply(3.14));


    }

    @Test
    public void test03() {

        // 情况二 : 类 :: 非静态方法
        // Comparator 中的 int compare(T t1, T t2)
        // String 中的 int t1.compareTo(t2)

        Comparator<String> com1 = (a, b) -> a.compareTo(b);
        System.out.println(com1.compare("a", "b"));

        System.out.println("使用方法引用如下:");
        Comparator<String> com2 = String::compareTo;
        System.out.println(com1.compare("a", "b"));

    }

    @Test
    public void test04() {

        // 构造器引用
        // Supplier 中的 T get()

        Supplier<Object> supplier1 = new Supplier<Object>() {
            @Override
            public Object get() {
                return new Object();
            }
        };
        System.out.println(supplier1.get());
        System.out.println("使用方法引用如下:");
        Supplier<Object> supplier2 = Object::new;
        System.out.println(supplier2.get());



        // 数组引用
        // Function 中的 R apply(T t)

        Function<Integer, String[]> func1 = length -> new String[length];
            String[] strings = func1.apply(6);
            System.out.println(Arrays.toString(strings));
            System.out.println("使用方法引用如下:");
            Function<Integer, String[]> func2 = String[] ::new;
            String[] strings2 = func1.apply(6);
            System.out.println(Arrays.toString(strings2));

            }
            }

四、Stream 流

1、概念

Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
stream 流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲究的是数据,流讲究的是计算!

2、操作步骤

  1. 创建 Stream :一个数据源(如:集合、数组),获取一个流
  2. 中间操作:一个中间操作链,对数据源的数据进行处理
  3. 终止操作(终端操作)

image.png

3、特点

  1. Stream 关注的是对数据的运算,CPU 打交道;集合关注的是数据的存储,与内存打交道
  2. Stream 流
    1. 不会自己存储元素
    2. 不会改变数据源。相反,他们会返回一个持有结果的 Stream 流
    3. 操作是延迟执行的,这意味着他们会等到需要结果的时候执行
  3. Stream 执行流程
    1. stream 的实例化
    2. 一系列的中间操作(过滤、映射、......)
    3. 终止操作
  4. 说明
    1. 一个中间操作链,对数据源的数据进行处理
    2. 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。(需重新执行

4、Stream 流创建方式

创建方式一:通过集合创建 Stream 流
创建方式一:通过数组创建 Stream 流
创建方式一:通过 Stream 流的静态方法 of( ) 创建
创建方式一:由函数创建流:创建无限流

	/**
     * 通过集合创建 Stream 流
     */
    @Test
    public void createStreamByCollection() {
        List<String> list = Arrays.asList("aaa","bbb","ccc");
        // 1.串行流
        Stream<String> stream = list.stream();

        // 2.并行流
        Stream<String> parallelStream = list.parallelStream();

    }

    /**
     * 通过数组创建 Stream 流
     */
    @Test
    public void createStreamByArray() {
        int[] arr = new int[]{1,2,3,4,5,6};
        // 调用 Arrays 类的静态方法 stream
        IntStream stream = Arrays.stream(arr);

    }


    /**
     * 通过 Stream 流的 静态方法of() 创建
     */
    @Test
    public void createStreamByOf() {
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);

    }


    /**
     * 由函数创建流:创建无限流
     */
    @Test
    public void createStream() {
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        // 迭代
        //public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        Stream.iterate(0,t -> t + 2).limit(10).forEach(System.out::println);

        // 生成
        // public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);

    }

5、Stream 流的中间操作

筛选与切片

  • filter(Predicate p) 接收Lambda,从流中排除某些元素。
  • limit(n) 截断流,使其元素不超过给定数量。
  • skip(n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit()互补。
  • distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素。
public class StreamAPITest2 {

	/**
     * 筛选与切片
     */
    @Test
    public void test() {

        List<String> list = Arrays.asList("李华","小明","小红","小王","李华");
        System.out.println(list);
        System.out.println("*************************");


        // filter(Predicate p) 接收Lambda,从流中排除某些元素。
        List<String> filterList = list.stream().filter(e -> !e.equals("李华")).collect(Collectors.toList());
        System.out.println(filterList);
        System.out.println("*************************");


        // limit(n) 截断流,使其元素不超过给定数量。
        System.out.println(list.stream().limit(2).collect(Collectors.toList()));
        System.out.println("*************************");

        // skip(n) 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit()互补.
        System.out.println(list.stream().skip(2).collect(Collectors.toList()));
        System.out.println("*************************");

        // distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
        System.out.println(list);
        System.out.println(list.stream().distinct().collect(Collectors.toList()));
        System.out.println("*************************");

    }
}

image.png

映射

  • **map(Function f) **:接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap(Function f) :接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
  • mapToDouble(ToDoubleFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
  • mapToInt(ToIntFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
  • mapToLong(ToLongFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
	/**
     * map 与 flatMap映射
     */
    @Test
    public void testMap() {
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");

        // map(Function f)  接收一个函数作为参数,将元素转换成其他形式或提取信息,
        // 该函数会被应用到每个元素上,并将其映射成一个新的元素。
        // System.out.println(list.stream().map(str -> str.toUpperCase()).collect(Collectors.toList()));

        System.out.println(list.stream().map(String::toUpperCase).collect(Collectors.toList()));

        // flatMap(Function f)  接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
        // 未使用 flatMap
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest2::formStringToStream);
        streamStream.forEach(s -> {
            s.forEach(System.out::println);
        });
        System.out.println("****************************");
        // 使用 flatMap
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest2::formStringToStream);
        characterStream.collect(Collectors.toList()).forEach(System.out::println);

    }

    public static Stream<Character> formStringToStream(String str) {
        List<Character> list = new ArrayList<>();
        char[] chars = str.toCharArray();
        for (char c : chars) {
            list.add(c);
        }
        return list.stream();
    }

image.png

排序

  • sorted() 自然排序
  • sorted(Comparator com) 定制排序
 /**
     * 排序
     */
    @Test
    public void testSort() {
        // sorted() 自然排序
        List<Integer> integerList = Arrays.asList(12, 23, -12, 32, 55, 66, 11);
        integerList.stream().sorted().forEach(System.out::println);
        System.out.println("***************************");

        // sorted(Comparator com) 定制排序
        integerList.stream().sorted( (x,y) -> Integer.compare(y,x)).forEach(System.out::println);
    }

image.png

6、Stream 的终止操作

查找与匹配

  • allMatch(Predicate p) :检查是否匹配所有元素
  • anyMatch(Predicate p):检查是否至少匹配一个元素
  • noneMatch(Predicate p):检查是否没有匹配所有元素
  • findFirst():返回第一个元素
  • findAny():返回当前流中的任意元素
  • count():返回流中元素总数
  • max(Comparator c):返回流中最大值
  • min(Comparator c):返回流中最小值
  • forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)

归约

  • reduce(T t, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
  • reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional
	/**
     * 终止操作 : 归约
     */
    @Test
    public void testReduce() {
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        // reduce(T t, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
        System.out.println(integerList.stream().reduce(0, Integer::sum));


        // reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
        // System.out.println(integerList.stream().reduce((a, b) -> a + b));
        System.out.println(integerList.stream().reduce(Integer::sum));

    }

image.png

收集

  • collect(Collector c):将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
/**
* 终止操作 : 收集
*/
@Test
    public void testCollect() {
    List<Integer> integerList = Arrays.asList(1, 2, 2, 2, 3, 4);
    // toList
    System.out.println(integerList.stream().skip(1).collect(Collectors.toList()));

    // toSet
    System.out.println(integerList.stream().skip(1).collect(Collectors.toSet()));

}

image.png

五、Optional 类

Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

常用方法

Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional文章来源地址https://www.toymoban.com/news/detail-653445.html

到了这里,关于【技术积累】Java 8 新特性的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 8 新特性——Lambda 表达式(2)

            Java Stream函数式编程接口最初在Java 8中引入,并且与 lambda 一起成为Java开发里程碑式的功能特性,它极大的方便了开放人员处理集合类数据的效率。         Java Stream就是一个数据流经的管道,并且在管道中对数据进行操作,然后流入下一个管道。有学过linux

    2024年02月11日
    浏览(30)
  • Java8新特性-Lambda表达式

    Lambda表达式 Lambda是一个匿名函数, 可以把lambda表达式理解为是一段可以传递的代码,(将代码像数据一样传递) 变化 需求: 求 薪资高于5000的员工信息 Lambda基本语法 在 java8 中引入了一个新的操作符 \\\"-\\\" , 箭头操作符, 箭头操作符 将Lambda表达式拆分为两部分: 左侧: Lambda表达式的参

    2024年02月01日
    浏览(32)
  • Java8新特性—Lambda表达式

    Java 8是Java编程语言的一个版本,于2014年发布。它引入了许多新的特性和改进。 Lambda表达式是Java 8中引入的一个重要的新特性,它提供了一种更加简洁、灵活的方式来编写函数式接口的实现,从而提高了代码的可读性和简洁性。 在本文中,我们将介绍Lambda表达式的基本语法、

    2024年02月03日
    浏览(34)
  • Java 8 新特性之Lambda表达式

    函数式编程(Functional Programming)是把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数。历史上研究函数式编程的理论是Lambda演算,所以我们经常把支持函数式编程的编码风格称为Lambda表达式。 在Java中使用Lambda表达式的前提:需要是函数接口。

    2024年01月22日
    浏览(36)
  • Java8新特性1——函数式接口&lambda表达式

    注:以下内容基于Java 8,所有代码都已在Java 8环境下测试通过 目录: Java8新特性1——函数式接口lambda表达式 Java8新特性2——方法引用 Java8新特性3——Stream 如果在一个接口中, 有且只有一个抽象方法 ,则该接口被称为函数式接口。如: 注: 可以在接口前使用 @FunctionalInt

    2024年02月10日
    浏览(34)
  • 【Java系列】JDK 1.8 新特性之 Lambda表达式

    Lambda是一个匿名函数,我们可以将Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递)。使用它可以写出简洁、灵活的代码。作为一种更紧凑的代码风格,使java语言表达能力得到提升。 结果: ​19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是没有使用Lambda表

    2024年02月22日
    浏览(39)
  • Java—JDK8新特性—Lambda表达式【内含思维导图】

    目录 JDK8新特性 2.Lambda表达式 思维导图 2.1 什么是Lambda表达式 2.2 为什么使用Lamdba表达式 2.3 Lambda表达式基本语法 2.4 类型推断 2.5 Lambda练习 2.6 Lambda常用场景         官网提供网址:JDK 8 Features         Lamdba是一个 匿名函数 ,可以把Lamdba表达式理解为是一段可以传递的

    2024年02月03日
    浏览(34)
  • 【技术积累】Java 8 新特性

    Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升 ( o1 , o2 ) - Integer.compare( o1 , o2 ) - : lambda 操作符或箭头操作符 - 左边

    2024年02月12日
    浏览(44)
  • Java 8及以上新特性:Lambda表达式、Stream API、Optional类与接口默认方法(四)

    目录 一、接口默认方法 1.1 概念解析: 1.2 应用场景: 1.3 使用注意事项: 1.4 使用示例: 二、结论 1.1 总结Java 8及以上版本四大新特性的重要意义与价值: 1.2 鼓励读者积极学习并运用这些新特性: 1.3 对未来Java版本可能引入的新特性进行展望: 1.1 概念解析: 接口默认方法

    2024年04月13日
    浏览(35)
  • java学习路程之篇三、进阶知识、面向对象高级、接口新特性、代码块、内部类、Lambda表达式、窗体、组件、事件

    概述 生成值类型响应式数据 通过 .value 值修改 生成对象和数组类型的响应式对象选用 reactive 方式比较好 html JavaScript 概述 reactive 方法根据传入的对象,创建返回一个深度响应式对象。响应式对象看起来和传入的对象一样。但是,响应式对象属性值改动,不管层级有多深,都

    2024年02月16日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包