java8
java8新特性简介:
速度更快
代码更少(增加了新的语法Lambda表达式)
强大的Stream API
便于并行
最大化减少空指针异常Optional
其中最为核心的为Lambda表达式与Stream API
Lambda表达式 Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使java的语言表达能力得到了提升。
java8中引入了一个新的操作符 -> 该操作符称为箭头操作符或Lmabda操作符,箭头操作符将Lambda表达式拆分成两部分:
左侧:lambda表达式的参数列表
右侧:Lambda表达式中所需要执行的功能,即Lambda体
语法一:无参数,无返回值 () -> System.out.print(“Hello Lambda”);
@Test public void test1 () { Runnable runnable1 = () -> System.out.println("Hello World" ); runnable1.run(); }
语法二:有一个参数,无返回值 (x) -> System.out.println(x)
Consumer接口:有一个参数,无返回值
@FunctionalInterface public interface Consumer <T> { void accept (T t) ; }
@Test public void test1 () { Consumer<String> consumer = (x) -> System.out.println(x); consumer.accept("Hello World" ); }
语法三:若只有一个参数,小括号可以省略不写 x -> System.out.println(x)
@Test public void test1 () { Consumer<String> consumer = x -> System.out.println(x); consumer.accept("Hello World" ); }
语法四:有两个以上的参数,有返回值,并且Lambda体中有多条语句
Comparator接口:有两个参数,有返回值
@FunctionalInterface public interface Comparator <T> { int compare (T o1, T o2) ; }
@Test public void test1 () { Comparator<Integer> comparator = (x, y) -> { System.out.println("函数式接口" ); return Integer.compare(x,y); }; }
语法五:若Lambda体中只有一条语句,return 和 大括号都可以省略不写
@Test public void test1 () { Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y); }
语法六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即类型推断。
(Integer x,Integer y) -> Integer.compare(x,y);
@Test public void test1 () { Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y); }
函数式接口 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。使用注解@FunctionalInterface修饰。
JDK 1.8 新增加的函数接口:java.util.function
Consumer
代表了接受一个输入参数并且无返回的操作
@FunctionalInterface public interface Consumer <T> { void accept (T t) ; }
public void happy (double money,Consumer<Double> consumer) { consumer.accept(money); } @Test public void test1 () { happy(1000 ,x -> System.out.println("大保健消费了" +x+"元" )); }
Supplier
无参数,返回一个结果。
@FunctionalInterface public interface Supplier <T> { T get () ; }
public List<Integer> getNumList (int num, Supplier<Integer> supplier) { List<Integer> list = new ArrayList <>(); for (int i = 0 ; i < num; i++) { Integer n = supplier.get(); list.add(n); } return list; } @Test public void test1 () { List<Integer> list = getNumList(5 , () -> (int ) (Math.random() * 100 )); for (Integer num:list){ System.out.println(num); } }
Function<T,R>
接受一个输入参数,返回一个结果。
@FunctionalInterface public interface Function <T, R> { R apply (T var1) ; }
public String strHandler (String str, Function<String,String> function) { return function.apply(str); } @Test public void test1 () { String s = strHandler("\t\t\t hello World" , (str) -> str.trim().substring(2 ,5 )); System.out.println(s); }
Predicate
接受一个输入参数,返回一个布尔值结果。
@FunctionalInterface public interface Predicate <T> { boolean test (T var1) ; }
public List<String> filterStr (List<String> list,Predicate<String> predicate) { List<String> strList = new ArrayList <>(); for (String str:list){ if (predicate.test(str)){ strList.add(str); } } return strList; } @Test public void test () { List<String> list=Arrays.asList("hello" ,"world" ,"ok" ,"lambda" ); List<String> stringList = filterStr(list, (s) -> s.length() > 3 ); for (String str:stringList){ System.out.println(str); } }
方法引用与构造器引用 方法引用 方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用方法引用。
可以理解为方法引用是Lambda表达式的另外一种表达形式。
注意:Lambda体中被调用的方法的参数列表和返回值类型需要与函数式接口中抽象方法的参数列表和返回值类型要一致。
主要有三种语法格式:
对象名::实例方法名
Consumer接口(有一个参数,无返回值)
@FunctionalInterface public interface Consumer <T> { void accept (T t) ; }
PrintStream的println方法(有一个参数,无返回值)
public void println (String var1) { synchronized (this ) { this .print(var1); this .newLine(); } }
@Test public void test () { PrintStream ps1 = System.out; Consumer<String> consumer = (x) -> ps1.println(x); PrintStream ps2 = System.out; Consumer<String> consumer2= ps2::println; Consumer<String> consumer3= System.out::println; consumer3.accept("aaaa" ); }
import lombok.AllArgsConstructor;import lombok.Data;@Data @AllArgsConstructor public class Employee { private String name; private int age; private double salary; }
@Test public void test () { Employee employee=new Employee (); String name=employee.getName(); int age=employee.getAge(); Supplier<String> supplier= () -> name; Supplier<String> supplier2= () -> age; Supplier<Integer> supplier3= employee::getAge; Integer num = supplier3.get(); System.out.println(num); }
类名::静态方法名
Integer类的compare静态方法源码如下:
public static int compare (int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1 ); }
Comparator接口
@FunctionalInterface public interface Comparator <T> { int compare (T o1, T o2) ; }
@Test public void test () { Comparator<Integer> comparator= (x,y) -> Integer.compare(x,y); Comparator<Integer> comparator2= Integer::compare; }
类名::实例方法名
若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
BiPredicate 函数式接口,接受两个参数返回一个boolean类型
@FunctionalInterface public interface BiPredicate <T, U> { boolean test (T t, U u) ; }
String类的equals方法源码如下:
public boolean equals (Object anObject) { if (this == anObject) { return true ; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0 ; while (n-- != 0 ) { if (v1[i] != v2[i]) return false ; i++; } return true ; } } return false ; }
@Test public void test () { BiPredicate<String,String> biPredicate=(x,y) -> x.equals(y); BiPredicate<String,String> biPredicate2=String::equals; }
构造器引用 格式:类名::new
需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
Function函数式接口,有一个参数,一个返回值
@FunctionalInterface public interface Function <T, R> { R apply (T t) ; }
BiFunction函数式接口,有两个参数,一个返回值
@FunctionalInterface public interface BiFunction <T, U, R> { R apply (T t, U u) ; }
Employee类,使用到其中的无参构造器,一个参数的构造器,两个参数的构造器
public class Employee { private int id; private String name; private int age; private double salary; public Employee () {} public Employee (int id) { this .id = id; } public Employee (int id, int age) { this .id = id; this .age = age; } public Employee (String name, int age, double salary) { this .name = name; this .age = age; this .salary = salary; } }
@Test public void test () { Supplier<Employee> sub = () -> new Employee (); sub.get(); Supplier<Employee> sub2 = Employee::new ; Employee employee = sub2.get(); System.out.println(employee); Function<Integer,Employee> function=(x) -> new Employee (x); Function<Integer,Employee> function2=Employee::new ; BiFunction<Integer,Integer,Employee> bf=Employee::new ; }
数组引用 格式:类型::new
@Test public void test () { Function<Integer,String[]> function=(x) -> new String [x]; String[] apply = function.apply(10 ); System.out.println(apply.length); Function<Integer,String[]> function2=String[]::new ; String[] apply2 = function.apply(20 ); System.out.println(apply2.length); }
Stream API Stream API ( java.util.stream.* )
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之, Stream API 提供了 一种高效且易于使用的处理数据的方式。
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
流(Stream)是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。集合讲的是数据,流讲的是计算!
Stream(流)是一个来自数据源的元素队列并支持聚合操作
元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
Pipelining : 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代 : 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
注意:
Stream操作的三个步骤:
通过Collection系列集合提供的Stream()或paralleStream()
List<String> list=new ArrayList <>(); Stream<String> stream = list.stream();
通过Arrays中的静态方法stream()获取数组流
Employee[] employee=new Employee [10 ]; Stream<Employee> stream = Arrays.stream(employee);
通过Stream类中的静态方法 of()
Stream<String> stream = Stream.of("aa" , "bb" , "cc" );
创建无限流
Stream<Integer> stream = Stream.iterate(0 , (x) -> x + 2 ); Stream<Double> stream = Stream.generate(() -> Math.random());
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”
中间操作:filter、limit、skip、distinct、map、flatMap、sorted
终止操作:allMatch,anyMatch,noneMatch, findFirst,findAny,count,max,min, reduce,collect
package com.didispace.chapter11;import java.util.Objects;public class User { private Integer id; private String name; private Integer age; public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public User (Integer id, String name, Integer age) { this .id = id; this .name = name; this .age = age; } @Override public boolean equals (Object o) { if (this == o) { return true ; } if (o == null || getClass() != o.getClass()) { return false ; } User that = (User) o; return Objects.equals(name, that.name) && Objects.equals(age, that.age); } @Override public int hashCode () { return Objects.hash(name, age); } }
package com.didispace.chapter11;import org.junit.Test;import java.util.*;import java.util.stream.Collectors;import java.util.stream.Stream;public class java8Test { List<User> userList= Arrays.asList( new User (1 ,"aa" ,18 ), new User (2 ,"bb" ,30 ), new User (3 ,"cc" ,40 ), new User (4 ,"dd" ,50 ), new User (5 ,"dd" ,50 ) ); @Test public void test () { Stream<User> satisfy = userList.stream().filter(e -> e.getAge() > 18 ); System.out.println("满足条件用户列表:" + satisfy.collect(Collectors.toList())); Stream.of(11 , 12 , 13 , 14 , 15 ).limit(3 ).forEach(System.out::println); List<Integer> collect1 = Stream.of(1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ).skip(5 ).collect(Collectors.toList()); List<Integer> users = userList.stream().map(User::getId).collect(Collectors.toList()); System.out.println("用户id列表:" + users); List<Integer> numbers = Arrays.asList(1 , 2 , 3 , 4 , 5 , 5 , 5 , 5 , 6 , 7 ); List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList()); System.out.println("distinctNumbers" +distinctNumbers); List<User> users1 = userList.stream().distinct().collect(Collectors.toList()); System.out.println("users1" + users1); List<String> names = userList.stream().map(User::getName).collect(Collectors.toList()); System.out.println("names" +names); List<String> list1 = Arrays.asList("aaa" , "bbb" , "ccc" , "eee" ); List<String> list2 = list1.stream().map(String::toUpperCase).collect(Collectors.toList()); System.out.println("list2:" +list2); List<Integer> length = userList.stream().map(User::getName).map(String::length).collect(Collectors.toList()); System.out.println("length" +length); List<Integer> age = userList.stream().map(User::getAge).map(i -> i - 10 ).collect(Collectors.toList()); System.out.println("age" +age); List<String> list3 = Arrays.asList("ccc" ,"aaa" , "bbb" , "ddd" , "eee" ); List<String> list4 = list3.stream().sorted().collect(Collectors.toList()); System.out.println("list4:" +list4); List<User> sorted = userList.stream().sorted((e1, e2) -> { if (e1.getAge() == e2.getAge()) { return e1.getName().compareTo(e2.getName()); } else { return -e1.getName().compareTo(e2.getName()); } }).collect(Collectors.toList()); System.out.println("sorted" +sorted); boolean allMatch = userList.stream().allMatch((e) -> e.getName().equals("bb" )); System.out.println("allMatch:" +allMatch); boolean anyMatch = userList.stream().anyMatch((e) -> e.getName().equals("bb" )); System.out.println("anyMatch:" +anyMatch); boolean noneMatch = userList.stream().noneMatch((e) -> e.getName().equals("bb" )); System.out.println("noneMatch:" +noneMatch); String[] strs = {"aaa" ,"bbb" ,"ccc" ,"ddddd" ,"abcdefg" }; Optional<String> first = Stream.of(strs).findFirst(); System.out.println("获取第一个元素 : " +first.get()); Optional<String> any = Stream.of(strs).findAny(); System.out.println("获取任意一个元素 :" +any.get()); long count = userList.stream().count(); System.out.println("count:" +count); Optional<User> optional = userList.stream().max((e1, e2) -> Double.compare(e1.getId(), e2.getId())); System.out.println("max最大值:" +optional.get()); Optional<Integer> optional2 = userList.stream().map(User::getId).min(Double::compare); System.out.println("max最大值:" +optional2.get()); Integer totalScore1 = userList.stream().map(User::getAge).reduce(0 ,(a,b) -> a + b); System.out.println("totalScore1:" +totalScore1); List<Integer> list6=Arrays.asList(1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ); Integer sum = list6.stream().reduce(0 , (x, y) -> x + y); System.out.println("sum:" +sum); Optional<Integer> optional3 = userList.stream().map(User::getId).reduce(Integer::sum); System.out.println("optional3:" +optional3.get()); Optional<Integer> max = userList.stream().map(User::getAge).reduce(Integer::max); Optional<Integer> min = userList.stream().map(User::getAge).reduce(Integer::min); System.out.println("max:" +max); System.out.println("min:" +min); List<Integer> list = userList.stream().map(User::getId).collect(Collectors.toList()); System.out.println("用户列表为: " + list); Map<Integer, String> map = userList.stream().collect(Collectors.toMap(User::getId, User::getName)); System.out.println("用户map为: " + map); userList.forEach(user -> System.out.println(user.getId())); } }
package com.didispace.chapter11;public class Employee { private int id; private String name; private int age; private double salary; private Status status; public enum Status { FREE, BUSY, VOCATION; } public Employee ( String name, int age, double salary, Status status) { this .name = name; this .age = age; this .salary = salary; this .status = status; } public Employee () {} public Employee (int id) { this .id = id; } public Employee (int id, int age) { this .id = id; this .age = age; } public Employee (String name, int age, double salary) { this .name = name; this .age = age; this .salary = salary; } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public double getSalary () { return salary; } public void setSalary (double salary) { this .salary = salary; } public Status getStatus () { return status; } public void setStatus (Status status) { this .status = status; } }
package com.didispace.chapter11;import org.junit.Test;import java.util.*;import java.util.stream.Collectors;public class ChapterTest { List<Employee> employees= Arrays.asList( new Employee ("张三" ,18 ,9999.99 , Employee.Status.FREE), new Employee ("李四" ,38 ,5555.99 ,Employee.Status.BUSY), new Employee ("王五" ,50 ,6666.66 ,Employee.Status.VOCATION), new Employee ("赵六" ,16 ,3333.33 ,Employee.Status.FREE), new Employee ("田七" ,8 ,7777.77 ,Employee.Status.BUSY) ); @Test public void test () { List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList()); list.forEach(System.out::println); Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toSet()); set.forEach(System.out::println); HashSet<String> hashSet = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new )); hashSet.forEach(System.out::println); Long count = employees.stream().collect(Collectors.counting()); System.out.println(count); Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg); Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); Optional<Employee> optional = employees.stream().collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(optional.get()); Optional<Double> optional2 = employees.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare)); System.out.println(optional2.get()); Map<Employee.Status, List<Employee>> map2 = employees.stream().collect(Collectors.groupingBy(Employee::getStatus)); System.out.println(map2); Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream() .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> { if (e.getAge() <= 35 ) { return "青年" ; } else if (e.getAge() <= 50 ) { return "中年" ; } else { return "老年" ; } }))); System.out.println(map); Map<Boolean, List<Employee>> map3 = employees.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000 )); System.out.println(map3); DoubleSummaryStatistics statistics = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary)); System.out.println(statistics.getSum()); System.out.println(statistics.getMax()); System.out.println(statistics.getAverage()); System.out.println(statistics.getCount()); System.out.println(statistics.getMin()); String s = employees.stream().map(Employee::getName).collect(Collectors.joining("," )); System.out.println(s); } }
Optional类 Optional< T>类java.util.Optional是一个容器类,代表一个值存在或不存在。原来用null表示一个值不存在,现在 Optional可以更好的表达这个概念。并且可以避免空指针异常。
Optional.of(T t) : 创建一个 Optional 实例
@Test public void test () { Optional<Employee> optional = Optional.of(new Employee ()); Employee employee = optional.get(); } public static <T> Optional<T> of (T value) { return new Optional <>(value); } private final T value;public T get () { if (value == null ) { throw new NoSuchElementException ("No value present" ); } return value; }
Optional.empty() : 创建一个空的 Optional 实例
@Test public void test () { Optional<Object> optional = Optional.empty(); Object o = optional.get(); } private static final Optional<?> EMPTY = new Optional <>();public static <T> Optional<T> empty () { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
@Test public void test () { Optional<Employee> optional = Optional.ofNullable(new Employee ()); Employee employee = optional.get(); } public static <T> Optional<T> ofNullable (T value) { return value == null ? empty() : of(value); }
@Test public void test () { Optional<Employee> optional = Optional.ofNullable(new Employee ()); if (optional.isPresent()){ System.out.println(optional.get()); } } private final T value;public boolean isPresent () { return value != null ; }
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
@Test public void test () { Optional<Employee> optional = Optional.ofNullable(new Employee ()); Employee employee = optional.orElse(new Employee ("田七" , 8 , 7777.77 , Employee.Status.BUSY)); } private final T value;public T orElse (T other) { return value != null ? value : other; }
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
@Test public void test () { Optional<Employee> optional = Optional.ofNullable(new Employee ()); Employee employee = optional.orElseGet(() -> new Employee ()); } private final T value;public T orElseGet (Supplier<? extends T> other) { return value != null ? value : other.get(); }
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
@Test public void test () { Optional<Employee> optional = Optional.ofNullable(new Employee ("田七" ,8 ,7777.77 ,Employee.Status.BUSY)); Optional<String> optional1 = optional.map((e) -> e.getName()); String s = optional1.get(); } public <U> Optional<U> map (Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
@Test public void test () { Optional<Employee> optional = Optional.ofNullable(new Employee ("田七" ,8 ,7777.77 ,Employee.Status.BUSY)); Optional<String> stringOptional = optional.flatMap((e) -> Optional.of(e.getName())); String s = stringOptional.get(); } public <U> Optional<U> flatMap (Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }
接口中的默认方法与静态方法 新时间日期API 其他新特性