新特性的分类
Lambda表达式
介绍
Lambda表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理:函数式开发者非常熟悉这些概念。很多JVM平台上的语言(Groovy、Scala等)从诞生之日就支持Lambda表达式,但是Java开发者没有选择,只能使用匿名内部类代替Lambda表达式。
语法
package com.wujing.java8.lambda;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* @ClassName: LambdaLean
* @Description: 学习Lambda
*
* <code>
* 举例: (o1,o2) -> Integer.compare(o1,o2)
* 格式:
* -> : lambda 操作符,或者 箭头操作符
* ->左边: lambda形参列表(其实就是接口中的抽象方法的形参列表)
* ->右边: lambda体(其实就是重写的抽象方法的方法体)
*
* lambda 表达式的使用:(6中情况)
* 总结:
* ->左边: 形参列表的参数类型可以省略,参数只有一个,()也可以省略
* ->右边:使用一对{}包裹,若只有一条执行语句,存在return 语句,可以省略{}
*
* lambda表达式的本质:作为函数式接口的实例,接口实现类的实例,接口只有一个方法。
* </code>
*
* @Author liujiexin
* @Date 2021/5/30 10:41 下午
*/
public class LambdaLean {
/**
* @Description: 语法一: 无参,无返回值
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:49 下午
*/
@Test
public void test1(){
Runnable a = new Runnable(){
@Override
public void run() {
System.out.println("哈哈哈哈哈哈哈");
}
};
a.run();
// () -> System.out.println("你好"); 这个整体是一个对象
Runnable a2 = () -> System.out.println("你好");
a2.run();
}
/**
* @Description: 语法二: 需要一个参数,无返回值
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:58 下午
*/
@Test
public void test2(){
// 常规写法
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("常规写法:一个参数,无返回值");
// lambda 表达式
Consumer<String> consumer1 = (String s) -> System.out.println(s);
consumer1.accept("lambda表达式写法: 一个参数,无返回值");
}
/**
* @Description: 语法三:数据类型可以省略,编译器可以推断得出,成为"类型推断"
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:58 下午
*/
@Test
public void test3(){
// lambda 表达式,类型推断
Consumer<String> consumer1 = (s) -> System.out.println(s);
consumer1.accept("lambda表达式,类型推断写法: 一个参数,无返回值");
}
/**
* @Description: "类型推断"
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:58 下午
*/
@Test
public void testArray(){
// "类型推断"
ArrayList<String> list = new ArrayList<>();
}
/**
* @Description: 语法四:lambda表达式若只有一个小括号也可以省略。
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:58 下午
*/
@Test
public void test4(){
// lambda 表达式,省略小括号 (s) == s
Consumer<String> consumer1 = s -> System.out.println(s);
consumer1.accept("lambda表达式,类型推断写法: 一个参数,无返回值");
}
/**
* @Description: 语法五:需要两个或两个以上参数,多条执行语句,并且可以有返回值
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:58 下午
*/
@Test
public void test5(){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
int compare = comparator.compare(10, 20);
System.out.println("常规写法:"+compare);
Comparator<Integer> comparator1 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(comparator1.compare(4,3));
}
/**
* @Description: 语法六:若lambda体只有个一条语句,return 与大括号,可以省略
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/30 10:58 下午
*/
@Test
public void test6(){
Comparator<Integer> comparator1 = (o1,o2) -> o1.compareTo(o2);
System.out.println(comparator1.compare(4,45));
}
}
函数式接口(Functional)
概念
若一个接口只声明了一个抽象方法,则此接口称为 函数式接口
例如:
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
/**
* The <code>Runnable</code> interface should be implemented by any
* class whose instances are intended to be executed by a thread. The
* class must define a method of no arguments called <code>run</code>.
* <p>
* This interface is designed to provide a common protocol for objects that
* wish to execute code while they are active. For example,
* <code>Runnable</code> is implemented by class <code>Thread</code>.
* Being active simply means that a thread has been started and has not
* yet been stopped.
* <p>
* In addition, <code>Runnable</code> provides the means for a class to be
* active while not subclassing <code>Thread</code>. A class that implements
* <code>Runnable</code> can run without subclassing <code>Thread</code>
* by instantiating a <code>Thread</code> instance and passing itself in
* as the target. In most cases, the <code>Runnable</code> interface should
* be used if you are only planning to override the <code>run()</code>
* method and no other <code>Thread</code> methods.
* This is important because classes should not be subclassed
* unless the programmer intends on modifying or enhancing the fundamental
* behavior of the class.
*
* @author Arthur van Hoff
* @see java.lang.Thread
* @see java.util.concurrent.Callable
* @since JDK1.0
*/
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
语法
package com.wujing.java8.functional;
/**
* @ClassName: MyFunctional
* @Description: 自定义函数式接口
*
* <code>
* 只包含一个抽象方法的接口,称为函数式接口
*
* @FunctionalInterface 校验是否式函数式接口
* </code>
* @Author liujiexin
* @Date 2021/5/30 11:34 下午
*/
@FunctionalInterface
public interface MyFunctional {
void method1();
// 定义多个 抽象的方法后,将不是函数式的接口了
// Multiple non-overriding abstract methods found in interface com.wujing.java8.functional.MyFunctional
// void method2();
}
Java 内置四大核心函数式接口
消费型接口 Consumer void accept(T t);
供给型接口Supplier T get();
函数型接口 Function
判定型接口 Predicate
函数型接口 Function
判定型接口 Predicate
�
方法引用
package com.wujing.java8.methodRef;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @ClassName: MethodRefTest
* @Description: 方法引用
* 1、使用情景:当要传递给Lambda 体的操作,已经有实现的方法了,可以使用方法引用。
* 2、方法引用的本质上就是Lambda的表达式,而Lambda表达式作为函数式接口的实例,所以方法引用,
* 也就是函数式接口的实例
* 3、使用格式:类(或对象):: 方法名
* <p>
* 4、具体分为如下三种情况
* 对象 :: 非静态方法
* 类 :: 静态方法
* 类 :: 非静态方法(此时方法参数不一致时,第一个参数看参数是否是方法的调用者)
*
* 5、方法引用使用的要求:
* 要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!
* 仅适用于: 对象 :: 非静态方法、类 :: 静态方法
* @Author liujiexin
* @Date 2021/5/31 11:19 下午
*/
public class MethodRefTest {
/**
* @Description: 对象 :: 实例方法
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/31 11:28 下午
*/
@Test
public void test1() {
Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("Lambda 表达式写法");
Consumer<String> consumer1 = System.out::println;
consumer1.accept("引用对象写法");
}
/**
* @Description: 对象 :: 实例方法
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/31 11:28 下午
*/
@Test
public void test2() {
Person person = new Person("1", "张三", 20);
Supplier<String> supplier = () -> person.getName();
System.out.println(supplier.get());
Person person2 = new Person("1", "李四", 20);
Supplier<String> supplier1 = person2 :: getName;
System.out.println(supplier1.get());
}
/**
* @Description: 类 :: 静态方法
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/31 11:28 下午
*/
@Test
public void test3() {
Comparator<Integer> comparator = (i1,i2) -> Integer.compare(i1,i2);
System.out.println( comparator.compare(10, 20));
Comparator<Integer> comparator2 = Integer :: compare;
System.out.println( comparator2.compare(10, 20));
}
/**
* @Description: 类 :: 静态方法
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/31 11:28 下午
*/
@Test
public void test4() {
Function<Double, Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
System.out.println(function.apply(10.9));
Function<Double, Long> function1 = Math :: round;
System.out.println(function1.apply(10.5));
}
/**
* @Description: 类 :: 实例方法
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/5/31 11:28 下午
*/
@Test
public void test5() {
Comparator<String> comparator = (s1,s2) -> s1.compareTo(s2);
System.out.println( comparator.compare("a", "an"));
Comparator<String> comparator2 = String :: compareTo;
System.out.println( comparator.compare("a", "an"));
}
}
@Data
@AllArgsConstructor
class Person{
String id;
String name;
int age;
}
[
](https://github.com/WuJingJava/javase.git)
Stream API
介绍
Java 8引入了全新的Stream API。这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。
Stream API引入的目的在于弥补Java函数式编程的缺陷。对于很多支持函数式编程的语言,map()、reduce()基本上都内置到语言的标准库中了,不过,Java 8的Stream API总体来讲仍然是非常完善和强大,足以用很少的代码完成许多复杂的功能。
Stream和Collection区别
Collection是一种静态资源的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要面向CPU,通过CPU实现计算。
注意
Stream 自己不会存储数据
Stream 不会改变源对象,相反,他们还会返回一个持有结果的新Stream
Stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才执行
Stream 操作步骤
1、创建Stream
一个数据源(集合、数组),获取一个流
package com.wujing.java8.streamapi;
import org.junit.Test;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @ClassName: StreamAPI
* @Description: StreamAPI 测试
* @Author liujiexin
* @Date 2021/6/1 9:18 下午
*/
public class StreamCreat {
/**
* @Description: 创建Stream 对象 方式一:通过集合
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 9:46 下午
*/
@Test
public void test1(){
/**
* 区别 顺序流,顺序读取数据,并行流,并行读取数据
*/
List<String> list = new ArrayList<>();
// default Stream<E> stream() 顺序流
Stream<String> stream = list.stream();
// default Stream<E> stream() 并行流
Stream<String> parallelStream = list.parallelStream();
}
/**
* @Description: 创建Stream 对象 方式二:通过数组
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 9:46 下午
*/
@Test
public void test2(){
int[] arr = new int[]{1,2,3,4};
// public static IntStream stream(int[] array)
IntStream stream = Arrays.stream(arr);
}
/**
* @Description: 创建Stream 对象 方式三:Stream 的 of
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 9:46 下午
*/
@Test
public void test3(){
// public static<T> Stream<T> of(T... values)
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
}
/**
* @Description: 创建Stream 对象 方式四:创建无限流
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 9:46 下午
*/
@Test
public void test4(){
Stream.iterate(0, t->t+2).limit(10).forEach(System.out :: println);
}
}
2、中间操作
一个中间操作链,对数据源的数据进行处理
package com.wujing.java8.streamapi;
import com.wujing.java8.methodRef.Person;
import org.junit.Test;
import sun.security.pkcs11.P11TlsKeyMaterialGenerator;
import sun.security.rsa.RSASignature;
import javax.print.attribute.standard.PDLOverrideSupported;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* @ClassName: StreamAPIOperation
* @Description: Steam中间操作
* 筛选与切片
* filter 从流中排除某些元素
* limit 截断流 使元素不超过给定数量
* skip 在丢弃流的前n元素后,返回由该流的其余元素组成的流。 如果此流包含少于n元素,则将返回一个空流。
* distinct 返回由该流的不同元素(根据Object.equals(Object) )组成的流。 对于有序流,不同元素的选择是稳定的(对于重复元素,保留遇到顺序中最先出现的元素。)对于无序流,没有稳定性保证
* <p>
* 映射
* map 返回由将给定函数应用于此流的元素的结果组成的流。
* @Author liujiexin
* @Date 2021/6/1 10:02 下午
*/
public class StreamAPIOperation {
/**
* @Description: filter limit
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 11:28 下午
*/
@Test
public void test1() {
List<Person> list = Person.getPersons();
Stream<Person> stream = list.stream();
// filter(Predicate<? super T> predicate); 此处接收一个 predicate 的实现类
stream.filter(new Predicate<Person>() {
@Override
public boolean test(Person person) {
return person.getAge() > 39;
}
}).forEach(System.out::println);
// 使用lambda 表达式写法
Stream<Person> stream2 = list.stream();
stream2.filter(e -> e.getAge() > 39).forEach(System.out::println);
System.out.println("------------------limit---------------------");
// limit()
Stream<Person> streamLimit = list.stream();
streamLimit.limit(3).forEach(System.out::println);
}
/**
* @Description: skip distinct
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 11:28 下午
*/
@Test
public void test2() {
List<Person> list = Person.getPersons();
Stream<Person> stream = list.stream();
// skip 在丢弃流的前n元素后,返回由该流的其余元素组成的流。 如果此流包含少于n元素,则将返回一个空流。
stream.skip(9).forEach(System.out::println);
// distinct()
Stream<Person> stream2 = list.stream();
stream2.distinct().forEach(System.out::println);
}
/**
* @Description: 映射 map
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 11:28 下午
*/
@Test
public void test3() {
List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee", "ff");
Stream<String> stream = list.stream();
//
stream.map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(System.out::println);
System.out.println("------------------map---------------------");
Stream<String> stream2 = list.stream();
// <R> Stream<R> map(Function<? super T, ? extends R> mapper);
stream2.map(s -> s.toUpperCase()).forEach(System.out::println);
System.out.println("------------------map---------------------");
// 获取名字长度 大于3的 所有的名称
List<Person> personsList = Person.getPersons();
Stream<Person> streamPerson = personsList.stream();
Stream<String> stringStream = streamPerson.map(Person::getName);
stringStream.filter(s -> s.length() >= 3).forEach(System.out::println);
}
}
package com.wujing.java8.streamapi;
import com.wujing.java8.methodRef.Person;
import org.junit.Test;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;
/**
* @ClassName: StreamAPISorted
* @Description: StreamAPI排序
*
* sorted 排序 默认排序 升序
*
* @Author liujiexin
* @Date 2021/6/2 11:31 下午
*/
public class StreamAPISorted {
@Test
public void test1(){
List<Integer> list = Arrays.asList(1,3,5,50,6,7,80,70);
list.stream().sorted().forEach(System.out :: println);
System.out.println("-------------sorted---------------");
}
/**
* @Description: 排序 sorted
* 对于有序流,排序是稳定的。 对于无序流,没有稳定性保证
* @Param:
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 11:28 下午
*/
@Test
public void test5() {
List<Integer> list = Arrays.asList(10, 30, 2, 50, 4, 9);
Stream<Integer> stream = list.stream();
// 默认 按升序排序
stream.sorted().forEach(System.out::println);
System.out.println("------------------sorted---------------------");
Stream<Integer> stream2 = list.stream();
// 默认 按升序排序
stream2.sorted(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
}).forEach(System.out::println);
System.out.println("------------------lambda 表达式---------------------");
// lambda 表达式
Stream<Integer> stream3 = list.stream();
// 默认 按升序排序
stream3.sorted((o1, o2) -> o2.compareTo(o1)).forEach(System.out::println);
List<Person> personsList = Person.getPersons();
Stream<Person> streamPerson = personsList.stream();
// 默认 按升序排序
streamPerson
.sorted((p1, p2) -> {
Comparator<Object> compare = Collator.getInstance(java.util.Locale.CHINA);
return compare.compare(p2.getName(), p1.getName());
})
.forEach(System.out::println);
}
}
package com.wujing.java8.streamapi;
import com.wujing.java8.methodRef.Person;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* @ClassName: StreamAPIMap
* @Description: StreamAPIMap
* @Author liujiexin
* @Date 2021/6/2 10:53 下午
*/
public class StreamAPIMap {
/**
* @Description:
* 映射
* map(Function f) 接收一个函数作为参数,将元素转换成其他形式或提取信息,改函数会被应用到每个元素上,并将其映射成一个新的元素
*
* flatMap(Funciton f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连成一个流
*
*
* @return: void
* @Author: liujiexin
* @Date: 2021/6/1 11:28 下午
*/
@Test
public void test1(){
List<String> list = Arrays.asList("aa","bb","cc","dd","ee","ff");
Stream<String> stream = list.stream();
//
stream.map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(System.out :: println);
System.out.println("------------------map---------------------");
Stream<String> stream2 = list.stream();
// <R> Stream<R> map(Function<? super T, ? extends R> mapper);
stream2.map(s -> s.toUpperCase()).forEach(System.out :: println);
System.out.println("------------------map---------------------");
// 获取名字长度 大于3的 所有的名称
List<Person> personsList = Person.getPersons();
Stream<Person> streamPerson = personsList.stream();
Stream<String> stringStream = streamPerson.map(Person::getName);
stringStream.filter(s -> s.length() >= 3).forEach(System.out :: println);
System.out.println("------------map----to---flatMap------------------------------");
List<String> list2 = Arrays.asList("aa","bb","cc","dd","ee","ff");
Stream<Stream<Character>> streamStream = list2.stream().map(StreamAPIMap::fromStringToStream);
streamStream.forEach(s ->{
s.forEach(System.out :: println);
});
System.out.println("----------------flatMap------------------------------");
// flatMap
Stream<Character> streamStream2 = list2.stream().flatMap(StreamAPIMap::fromStringToStream);
streamStream2.forEach(System.out :: println);
}
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
@Test
public void test2(){
ArrayList list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
ArrayList list1 = new ArrayList();
list1.add(4);
list1.add(5);
list1.add(6);
list1.add(list);
}
}
3、终止操作
一旦执行终止操作,就执行中间操作链,并产生结果,之后不会再被使用。
package com.wujing.java8.streamapi;
import com.sun.imageio.plugins.common.I18N;
import com.sun.org.apache.bcel.internal.generic.RETURN;
import com.wujing.java8.methodRef.Person;
import org.junit.Test;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @ClassName: StreamAPIStop
* @Description: StreamAPI的终止操作
* @Author liujiexin
* @Date 2021/6/2 11:38 下午
*/
public class StreamAPIStop {
/**
* 功能描述: 匹配与查找 相关功能
*/
@Test
public void test1(){
/**
* allMatch(Predicate p ) 检查是否匹配所有的元素
*/
List<Person> persons = Person.getPersons();
boolean b = persons.stream().allMatch(p -> p.getAge() > 40);
System.out.println(b);
/**
* anyMatch(Predicate p ) 检查是否至少匹配一个元素
*/
boolean b2 = persons.stream().anyMatch(p -> p.getName().contains("赵六2") );
System.out.println(b2);
/**
* findFirst 返回第一个元素
*/
Optional<Person> first = persons.stream().findFirst();
System.out.println(first.toString());
/**
* findAny 返回当前流中的任意一个元素
*/
Optional<Person> any = persons.parallelStream().findAny();
System.out.println(any.toString());
/**
* count() 获取流中的总个数
*/
long count = persons.stream().filter(p -> p.getAge() > 60).count();
System.out.println(count);
/**
* max(Comparator c) 返回流中最大值
*/
Stream<Integer> integerStream = persons.stream().map(p -> p.getAge());
Optional<Integer> max = integerStream.max(Integer::compareTo);
System.out.println(max);
/**
* min(Comparator c) 返回流中最小值
*/
Optional<Person> min = persons.stream().min((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));
System.out.println(min.toString());
/**
* forEach(Consumer c)
*/
persons.stream().forEach(new Consumer<Person>() {
@Override
public void accept(Person person) {
System.out.println(person.toString());
}
});
System.out.println("----------------forEach(Consumer c)---------------------------");
persons.stream().forEach(System.out :: println);
}
/**
* 功能描述: 归约 reduce(求和)
*/
@Test
public void test2(){
/**
* T reduce(T identity, BinaryOperator<T> accumulator);
* 使用提供的标识值和关联累积函数对该流的元素执行归约,并返回归约后的值。 这相当于:
*
* T result = identity;
* for (T element : this stream)
* result = accumulator.apply(result, element)
* return result;
*/
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// 基本写法
Integer reduce = list.stream().reduce(0, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer + integer2;
}
});
System.out.println("-------------------基本写法--------------------------");
System.out.println(reduce);
// lambda 表达式写法
Integer reduce2 = list.stream().reduce(0, (i1, i2) -> i1+i2);
System.out.println("-------------------表达式写法--------------------------");
System.out.println(reduce);
// 方法引用的写法
Integer reduce3 = list.stream().reduce(0, Integer::sum);
System.out.println("-------------------方法引用的写法--------------------------");
System.out.println(reduce);
/**
* T reduce(BinaryOperator accumulator);
* 使用提供的标识值和关联累积函数对该流的元素执行归约,并返回归约后的值。 这相当于:
*
* T result = identity;
* for (T element : this stream)
* result = accumulator.apply(result, element)
* return result;
*/
List<Person> personList = Person.getPersons();
// 基本写法
Optional<Integer> reduce1 = personList.stream().map(new Function<Person, Integer>() {
@Override
public Integer apply(Person person) {
return person.getAge();
}
}).reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer i1, Integer i2) {
return i1 + i2;
}
});
System.out.println("---------------reduce----方法引用的写法--------------------------");
System.out.println(reduce1);
// lambda 表达式写法
Optional<Integer> reduce5 = personList.stream().map(person -> person.getAge()).reduce((i1, i2) -> i1 + i2);
System.out.println("---------------reduce----lambda 表达式写法--------------------------");
System.out.println(reduce5);
// 方法引用写法
Optional<Integer> reduce4 = personList.stream().map(Person::getAge).reduce(Integer::sum);
System.out.println("---------------reduce----方法引用写法--------------------------");
System.out.println(reduce4);
}
/**
* 功能描述: 收集 collect(Collector c)
*/
@Test
public void test3(){
List<Person> persons = Person.getPersons();
List<Person> collect = persons.stream()
.filter(person -> person.getAge() > 40)
.sorted((p1, p2) -> Integer.compare(p2.getAge(), p1.getAge()))
.collect(Collectors.toList());
collect.forEach(System.out :: println);
System.out.println("-------------------功能描述: 收集 collect(Collector c) toList---------------------------------------");
Set<Person> collect1 = persons.stream()
.filter(person -> person.getAge() > 40)
.sorted((p1, p2) -> Integer.compare(p2.getAge(), p1.getAge()))
.collect(Collectors.toSet());
collect1.forEach(System.out :: println);
System.out.println("-------------------功能描述: 收集 collect(Collector c) toSet---------------------------------------");
Map<Integer, Person> collect2 = persons.stream()
.filter(person -> person.getAge() > 40)
.sorted((p1, p2) -> Integer.compare(p2.getAge(), p1.getAge()))
.collect(Collectors.toMap(Person::getId, person -> person));
collect2.forEach((i, collec) -> {
System.out.println(collect2.get(i));
});
}
}
Optional 类
时间日期
1. Clock
Clock 提供对当前日期和时间的访问。我们可以利用它来替代 System.currentTimeMillis() 方法。另外,通过 clock.instant() 能够获取一个 instant 实例, 此实例能够方便地转换成老版本中的 java.util.Date 对象。
@Test public void test31(){
Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
Instant instant = clock.instant();
Date legacyDate = Date.from(instant);
// 老版本 java.util.Date
}
2. Timezones 时区
ZoneId 代表时区类。通过静态工厂方法方便地获取它,入参我们可以传入某个时区编码。另外,时区类还定义了一个偏移量,用来在当前时刻或某时间 与目标时区时间之间进行转换。
@Test public void test32() {
System.out.println(ZoneId.getAvailableZoneIds());
// prints all available timezone ids
ZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
System.out.println(zone1.getRules());
System.out.println(zone2.getRules());
//[Asia/Aden, America/Cuiaba, Etc/GMT+9, Etc/Gada/Atlantic, Atlantic/St_Helena, Australia/Tasmania, Libya, Europe/Guernsey, America/Grand_Turk, US/Pacific-New, Asia/Samarkand, America/Argentina/Cordoba, Asia/Phnom_Penh, Africa/Kigali, Asia/Almaty, US/Alaska, Asi...
// ZoneRules[currentStandardOffset=+01:00]
// ZoneRules[currentStandardOffset=-03:00]
}
3. LocalTime
LocalTime 表示一个没有指定时区的时间类,例如,10 p.m.或者 17:30:15,下面示例代码中,将会使用上面创建的 时区对象创建两个 LocalTime。然后我们会比较两个时间,并计算它们之间的小时和分钟的不同。
@Test public void test33(){
ZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
LocalTime now1 = LocalTime.now(zone1);
LocalTime now2 = LocalTime.now(zone2);
System.out.println(now1.isBefore(now2));
// false
long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);
System.out.println(hoursBetween);
// -3
System.out.println(minutesBetween);
// -239
}
LocalTime 提供多个静态工厂方法,目的是为了简化对时间对象实例的创建和操作,包括对时间字符串进行解析的操作等。
@Test public void test34(){
LocalTime late = LocalTime.of(23, 59, 59);
System.out.println(late);
// 23:59:59
DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(Locale.GERMAN);
LocalTime leetTime = LocalTime.parse("13:37", germanFormatter);
System.out.println(leetTime);
// 13:37
}
4. LocalDate
LocalDate 是一个日期对象,例如:2014-03-11。它和 LocalTime 一样是个 final 类型对象。下面的例子演示了如何通过加减日,月,年等来计算一个新的日期。
@Test public void test35(){
LocalDate today = LocalDate.now();
// 今天加一天
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
// 明天减两天
LocalDate yesterday = tomorrow.minusDays(2);
// 2014 年七月的第四天
LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);
DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
System.out.println(dayOfWeek);
// 星期五
}
也可以直接解析日期字符串,生成 LocalDate 实例。(和 LocalTime 操作一样简单)
@Test public void test36(){
DateTimeFormatter germanFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.GERMAN);
LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter);
System.out.println(xmas);
// 2014-12-24
}
5. LocalDateTime
LocalDateTime 是一个日期-时间对象。你也可以将其看成是 LocalDate 和 LocalTime 的结合体。操作上,也大致相同。
@Test public void test37(){
LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);
DayOfWeek dayOfWeek = sylvester.getDayOfWeek();
System.out.println(dayOfWeek);
// 星期三
Month month = sylvester.getMonth();
System.out.println(month);
// 十二月
// 获取改时间是该天中的第几分钟
long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);
System.out.println(minuteOfDay);
// 1439
}
如果再加上的时区信息,LocalDateTime 还能够被转换成 Instance 实例。Instance 能够被转换成老版本中 java.util.Date 对象。
@Test public void test38(){
LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);
Instant instant = sylvester.atZone(ZoneId.systemDefault()).toInstant();
Date legacyDate = Date.from(instant);
System.out.println(legacyDate);
// Wed Dec 31 23:59:59 CET 2014
}
格式化 LocalDateTime 对象就和格式化 LocalDate 或者 LocalTime 一样。除了使用预定义的格式以外,也可以自定义格式化输出。
@Test public void test39(){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy - HH:mm");
LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter);
String string = formatter.format(parsed);
System.out.println(string);
// Nov 03, 2014 - 07:13
}
Unlike java.text.NumberFormat the new DateTimeFormatter is immutable and thread-safe.
For details on the pattern syntax read here(opens new window).