asp.net 网站启动慢营销软文300字范文
Java SE 8 新增特性
作者:Grey
原文地址:
博客园:Java SE 8 新增特性
CSDN:Java SE 8 新增特性
源码
源仓库: Github:java_new_features
Lambda 表达式
Java SE 8 里面最大的更新莫过于支持 Lambda 表达式,Oracle 官网给了一个很好的示例说明,见:Lambda Expressions,以下示例参考了这个官方说明文档。
假设我们定义一个 Person 类,属性和方法如下
public class Person {String name;LocalDate birthday;Sex gender;String emailAddress;// 省略get/set方法public void printPerson() {// 打印Person信息}public static List<Person> createRoster() {// 获取Person列表}public enum Sex {MALE, FEMALE}
}
如果要获取某个年龄段的所有 Person 信息,我们可能会写出如下代码
// 查询大于age的所有人员信息
public static void printPersonsOlderThan(List<Person> roster, int age) {for (Person p : roster) {if (p.getAge() >= age) {p.printPerson();}}
}
// 查询年龄在[low, high)区间内的所有人员信息
public static void printPersonsWithinAgeRange(List<Person> roster, int low, int high) {for (Person p : roster) {if (low <= p.getAge() && p.getAge() < high) {p.printPerson();}}
}
这样写的缺点是扩展性不好,如果有新的规则,我们需要增加多个同样类型的方法。
更好的一种方式是,定义一个 Local Class,将规则分离出来,这样一来,规则无论如何变化,主流程的代码是不需要调整的,以上述例子来说明。我们定义如下接口
interface CheckPerson {boolean test(Person p);
}
这个接口用于抽象出规则的定义,在主流程中,我们把这个接口设计到参数中,代码如下:
public static void printPersons(List<Person> roster, CheckPerson tester) {for (Person p : roster) {if (tester.test(p)) {p.printPerson();}}
}
这样我们就做到了规则和主流程分离,比如我们要定义一个规则,只需要实现 CheckPerson 接口
// 年龄在[18,25]区间内的男性人员信息
class CheckPersonEligibleForSelectiveService implements CheckPerson {public boolean test(Person p) {return p.gender == Person.Sex.MALE &&p.getAge() >= 18 &&p.getAge() <= 25;}
}
在调用的时候,只需要把这个规则作为参数传入即可
printPersons(roster, new CheckPersonEligibleForSelectiveService());
上述示例还可以转换成匿名类的写法,如下:
printPersons(roster,new CheckPerson() {public boolean test(Person p) {return p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25;}}
);
也可以转换成 Java SE 8 中新增的 Lambda 表达式的写法,如下:
printPersons(roster,(Person p) -> p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25
);
由于 CheckPerson 这个接口只有一个方法,所以这又是一个函数式接口,在我们这个例子的场景下,我们可以用 Predicate<T>
来替换 CheckPerson 接口。因为 Predicate<T>
接口定义就是
interface Predicate<T> {boolean test(T t);
}
使用 Predicate<T>
以后,代码如下:
public static void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester) {for (Person p : roster) {if (tester.test(p)) {p.printPerson();}}
}
最后,代码又可以简化成如下形式:
printPersonsWithPredicate(roster,p -> p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25
);
printPersonsWithPredicate 方法重构成如下形式:
public static void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester) {for (Person p : roster) {if (tester.test(p)) {p.printPerson();}}
}
还可以做进一步的优化,我们可以指定一个不同的动作来执行那些满足条件的 Person 实例,而不是直接调用 printPerson 方法。可以用一个 Lambda 表达式来指定这个动作。这里引入了 Consumer 接口。
public static void processPersons(List<Person> roster,Predicate<Person> tester,Consumer<Person> block) {for (Person p : roster) {if (tester.test(p)) {block.accept(p);}}
}
这样,我们就把打印行为也给分离出来了,主流程调用的代码可以进一步简化成
processPersons(roster,p -> p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25,p -> p.printPerson()
);
经过上述重构和优化,我们可以定义不同条件下的不同行为
例如:
public static void processPersonsWithFunction(List<Person> roster,Predicate<Person> tester,Function<Person, String> mapper,Consumer<String> block) {for (Person p : roster) {if (tester.test(p)) {String data = mapper.apply(p);block.accept(data);}}
}
再如:
processPersonsWithFunction(roster,p -> p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25,p -> p.getEmailAddress(),email -> System.out.println(email)
);
可以做进一步的泛化:
public static <X, Y> void processElements(Iterable<X> source,Predicate<X> tester,Function <X, Y> mapper,Consumer<Y> block) {for (X p : source) {if (tester.test(p)) {Y data = mapper.apply(p);block.accept(data);}}
}
针对的场景就是一个集合,经过某些过滤,取出满足条件的数据,然后把这个数据进行加工,例如:
processElements(roster,p -> p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25,p -> p.getEmailAddress(),email -> System.out.println(email)
);
最后,使用 Stream ,让整个代码变的简洁优雅
roster.stream().filter(p -> p.getGender() == Person.Sex.MALE&& p.getAge() >= 18&& p.getAge() <= 25).map(p -> p.getEmailAddress()).forEach(email -> System.out.println(email));
除了可以使用 Lambda 表达式创建匿名方法,我们还可以使用方法引用来替代 lambda 表达式,这样可读性会好一些,例如:
public class Person {// ...public static int compareByAge(Person a, Person b) {return a.birthday.compareTo(b.birthday);}// ...
}
按年龄排序,我们既可以这样写:
// 定义比较器
class PersonAgeComparator implements Comparator<Person> {public int compare(Person a, Person b) {return a.getBirthday().compareTo(b.getBirthday());}
}
Arrays.sort(rosterAsArray, new PersonAgeComparator());
也可以使用 lambda 表达式
Arrays.sort(rosterAsArray,(Person a, Person b) -> {return a.getBirthday().compareTo(b.getBirthday());}
);
由于 Person 类中已经存在一个比较方法,我们可以通过方法引用来替代 Lambda 表达式
Arrays.sort(rosterAsArray,(a, b) -> Person.compareByAge(a, b)
);
这个 compareByAge 的参数列表和 Comparator<Person>.compare
方法的参数一致,可以简写成:
Arrays.sort(rosterAsArray, Person::compareByAge);
方法引用有如下几种类型
类型 | 语法 | 示例 |
---|---|---|
静态方法 | *ContainingClass*::*staticMethodName* | Person::compareByAge MethodReferencesExamples::appendStrings |
实例方法 | *containingObject*::*instanceMethodName* | myComparisonProvider::compareByName myApp::appendStrings2 |
对一个特定类型的任意对象的实例方法的引用 | *ContainingType*::*methodName* | String::compareToIgnoreCase String::concat |
构造方法 | *ClassName*::new | HashSet::new |
以下是示例
import java.util.function.BiFunction;/*** @since 1.8*/
public class MethodReferencesExamples {public static <T> T mergeThings(T a, T b, BiFunction<T, T, T> merger) {return merger.apply(a, b);}public static String appendStrings(String a, String b) {return a + b;}public String appendStrings2(String a, String b) {return a + b;}public static void main(String[] args) {MethodReferencesExamples myApp = new MethodReferencesExamples();// 使用 lambda 表达式System.out.println(MethodReferencesExamples.mergeThings("Hello ", "World!", (a, b) -> a + b));// 静态方法System.out.println(MethodReferencesExamples.mergeThings("Hello ", "World!", MethodReferencesExamples::appendStrings));// 实例方法System.out.println(MethodReferencesExamples.mergeThings("Hello ", "World!", myApp::appendStrings2));// 对一个特定类型的任意对象的实例方法的引用System.out.println(MethodReferencesExamples.mergeThings("Hello ", "World!", String::concat));}
}
接口支持默认方法和静态方法
直接看示例:
import java.time.*;public interface TimeClient {void setTime(int hour, int minute, int second);void setDate(int day, int month, int year);void setDateAndTime(int day, int month, int year,int hour, int minute, int second);LocalDateTime getLocalDateTime();
}
package defaultmethods;import java.time.*;
import java.lang.*;
import java.util.*;public class SimpleTimeClient implements TimeClient {private LocalDateTime dateAndTime;public SimpleTimeClient() {dateAndTime = LocalDateTime.now();}public void setTime(int hour, int minute, int second) {LocalDate currentDate = LocalDate.from(dateAndTime);LocalTime timeToSet = LocalTime.of(hour, minute, second);dateAndTime = LocalDateTime.of(currentDate, timeToSet);}public void setDate(int day, int month, int year) {LocalDate dateToSet = LocalDate.of(day, month, year);LocalTime currentTime = LocalTime.from(dateAndTime);dateAndTime = LocalDateTime.of(dateToSet, currentTime);}public void setDateAndTime(int day, int month, int year,int hour, int minute, int second) {LocalDate dateToSet = LocalDate.of(day, month, year);LocalTime timeToSet = LocalTime.of(hour, minute, second); dateAndTime = LocalDateTime.of(dateToSet, timeToSet);}public LocalDateTime getLocalDateTime() {return dateAndTime;}public String toString() {return dateAndTime.toString();}public static void main(String... args) {TimeClient myTimeClient = new SimpleTimeClient();System.out.println(myTimeClient.toString());}
}
上述代码中,如果要在接口中添加一个方法,那么所有实现这个接口的客户端都要重新实现这个方法,非常麻烦。
public interface TimeClient {void setTime(int hour, int minute, int second);void setDate(int day, int month, int year);void setDateAndTime(int day, int month, int year,int hour, int minute, int second);LocalDateTime getLocalDateTime();// 新增一个方法,所有的子类都要实现这个方法ZonedDateTime getZonedDateTime(String zoneString);
}
在 Java SE 8 中,接口可以支持默认方法,即:我们可以指定接口的某个方法的默认实现,这样的话,子类就不需要重写这个方法,可以使用接口的默认实现,同时,Java SE 8 中,接口也支持静态方法。
package defaultmethods;import java.time.*;public interface TimeClient {void setTime(int hour, int minute, int second);void setDate(int day, int month, int year);void setDateAndTime(int day, int month, int year,int hour, int minute, int second);LocalDateTime getLocalDateTime();// 接口也支持静态方法实现static ZoneId getZoneId (String zoneString) {try {return ZoneId.of(zoneString);} catch (DateTimeException e) {System.err.println("Invalid time zone: " + zoneString +"; using default time zone instead.");return ZoneId.systemDefault();}}// 默认实现,子类无须重写 default ZonedDateTime getZonedDateTime(String zoneString) {return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));}
}
通过上述改造,所有子类都具备了接口默认方法的能力,子类可以直接调用接口的默认实现。
package defaultmethods;import java.time.*;
import java.lang.*;
import java.util.*;public class TestSimpleTimeClient {public static void main(String... args) {// NOTE:SimpleTimeClient无须做任何改动TimeClient myTimeClient = new SimpleTimeClient();System.out.println("Current time: " + myTimeClient.toString());// 调用默认实现System.out.println("Time in California: " +myTimeClient.getZonedDateTime("Blah blah").toString());}
}
当然,默认实现也可以修改,子类重写默认实现就可以了。
此外,接口支持静态方法实现,上述接口中的静态方法,可以直接使用
TimeClient.getZoneId("zoneID");
接口可以支持静态方法这一特性扩展了接口的功能,但是对于实现这个接口的子类没有影响,比如 Comparator
类中的 comparing
方法,示例
myDeck.sort(Comparator.comparing(Card::getRank).thenComparing(Comparator.comparing(Card::getSuit)));
一些增强的 API
新增的包
java.util.function
java.util.stream
调整的包
包 | 新增类 | 有调整的类 |
---|---|---|
java.io | UncheckedIOException | BufferedReader |
java.lang | not applicable | AutoCloseable ThreadLocal String Iterable CharSequence Boolean Integer Long Float Double |
java.nio.file | not applicable | Files |
java.util | PrimitiveIterator Spliterator DoubleSummaryStatistics IntSummaryStatistics LongSummaryStatistics Optional OptionalDouble OptionalInt OptionalLong Spliterators SplittableRandom StringJoiner | Arrays BitSet Collection Comparator Iterator List Map Map.Entry LinkedHashMap Random TreeMap |
java.util.concurrent | not applicable | ThreadLocalRandom |
java.util.jar | not applicable | JarFile |
java.util.zip | not applicable | ZipFile |
java.util.logging | not applicable | Logger |
java.util.regex | not applicable | Pattern |
具体可参考:New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in Java SE 8
List 转 Map
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;// list转map
public class List2Map {/*** key name, value number*/static void sample1() {List<Car> list = new ArrayList<>();list.add(new Car("A", 1));list.add(new Car("B", 2));list.add(new Car("C", 3));// to map,key car name,value ,car numberMap<String, Integer> carMap = list.stream().collect(Collectors.toMap(Car::getName, Car::getNum));System.out.println(carMap);}/*** key name value object*/static void sample2() {List<Car> list = new ArrayList<>();list.add(new Car("A", 1));list.add(new Car("B", 2));list.add(new Car("C", 3));Map<String, Car> carMap = list.stream().collect(Collectors.toMap(Car::getName, car -> car));System.out.println(carMap);}/*** 处理重复数据 包含重复数据的时候,只保留最新的一条*/static void sample3() {List<Car> list = new ArrayList<>(4);list.add(new Car("A", 1));list.add(new Car("A", 2));list.add(new Car("B", 2));list.add(new Car("C", 3));Map<String, Integer> carMap = list.stream().collect(Collectors.toMap(Car::getName, Car::getNum, (oldData, newData) -> newData));System.out.println(carMap);}/*** 重复数据,包含重复数据的时候,只保留最新的一条,并把结果保存到ConcurrentHashMap*/static void sample4() {List<Car> list = new ArrayList<>();list.add(new Car("A", 1));list.add(new Car("A", 2));list.add(new Car("B", 2));list.add(new Car("C", 3));Map<String, Integer> carMap = list.stream().collect(Collectors.toMap(Car::getName, Car::getNum, (oldData, newData) -> newData, ConcurrentHashMap::new));System.out.println(carMap.getClass());}
}
class Car {private String name;private Integer num;// 省略get/set和构造方法
}
forEach 遍历
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;/*** for each遍历方式* @since 1.8*/
public class ForEachTest {// jdk8之前常规遍历操作static void normForEach() {List<String> list = Arrays.asList("a", "b", "c");for (String item : list) {System.out.println(item);}}static void newForEach() {List<String> list = Arrays.asList("a", "b", "c");list.forEach(System.out::println);list.forEach(s -> {System.out.println("新的遍历方式");System.out.println(s);});}// Map的遍历 jdk1.8之前static void mapNormForEach() {Map<Integer, String> map = new HashMap<>(3);map.put(1, "a");map.put(2, "b");map.put(3, "c");for (Map.Entry<Integer, String> entry : map.entrySet()) {System.out.println(entry.getKey() + ":\t" + entry.getValue());}}//jdk1.8新的Map遍历方法static void mapNewForEach() {Map<Integer, String> map = new HashMap<>(3);map.put(1, "a");map.put(2, "b");map.put(3, "c");map.forEach((k, v) -> {System.out.println(k);System.out.println(v);});}// jdk1.8新增数组的遍历方法static void arrayForEach() {String[] array = {"a", "b", "c"};Arrays.stream(array).forEach(System.out::println);}//不保证有序static void parallelForEach() {Stream<String> stream = Stream.of("ab", "bc", "cd");stream.parallel().forEach(System.out::println);}// 可以保证有序static void parallelForEachOrder() {Stream<String> stream = Stream.of("ab", "bc", "cd");stream.parallel().forEachOrdered(System.out::println);}// 使用consumerstatic void forEachUseConsumer() {Stream<String> s = Stream.of("ab", "bc");List<String> l = Arrays.asList("ab", "cd");Consumer<String> consumer = s1 -> {System.out.println(s1.toUpperCase());};s.forEach(consumer);l.forEach(consumer);}
}
Optional
用于优雅判断空。
import java.util.Optional;/*** Optional用法* @since 1.8*/
public class OptionalTest {static void handleNull() {//String s = null;//Optional<String> s1 = Optional.of(s);// System.out.println(s1.isPresent());Optional<String> hello = Optional.of("hello");Optional<Object> empty = Optional.empty();Optional<Object> nullObj = Optional.ofNullable(null);System.out.println(hello.isPresent());System.out.println(empty.isPresent());System.out.println(nullObj.isPresent());}static void emptyGetException() {try {Optional<String> hello = Optional.of("hello");System.out.println(hello.get());Optional<Object> empty = Optional.empty();System.out.println(empty.get());} catch (Exception e) {e.printStackTrace();}}static void orElseException() {try {Optional<String> emptyOptional = Optional.empty();String value = emptyOptional.orElseThrow(() -> new Exception("发现空值"));System.out.println(value);} catch (Exception e) {e.printStackTrace();}}static void orElseGet() {Optional<Object> empty = Optional.empty();Object o = empty.orElseGet(() -> "default");System.out.println(o);Object aDefault = empty.orElse("default");System.out.println(aDefault);}static void funcOptional() {Optional<Integer> optional123 = Optional.of(123);optional123.filter(num -> num == 123).ifPresent(num -> System.out.println(num));Optional<Integer> optional456 = Optional.of(456);optional456.filter(num -> num == 123).ifPresent(num -> System.out.println(num));// map 转换Optional<Integer> optional789 = Optional.of(789);optional789.map(String::valueOf).map(String::length).ifPresent(length -> System.out.println(length));}
}
新的时间处理类
package git.snippets.jdk8;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;import static java.time.temporal.ChronoUnit.DAYS;
/*** @since 1.8*/
//参考 https://www.wdbyte.com/2019/10/jdk/jdk8-time/
public class LocalDateTest {static void errorDate() {// 不合法的日期LocalDate invalidDate = LocalDate.of(2021, 2, 29);invalidDate.minusYears(1);System.out.println(invalidDate.minusYears(1));}static void until() {LocalDate birthday = LocalDate.of(1989, 9, 27);System.out.println(birthday.until(LocalDate.now(), DAYS));}// 有时区的精确时间static void zone() {ZonedDateTime nowZone = LocalDateTime.now().atZone(ZoneId.systemDefault());System.out.println("当前精确时间(有时区):" + nowZone);System.out.println("当前精确时间(有时区):" + nowZone.getYear() + "-" + nowZone.getMonthValue() + "-" + nowZone.getDayOfMonth() + " " + nowZone.getHour() + "-" + nowZone.getMinute() + "-" + nowZone.getSecond());}static void createTime() {LocalDateTime ofTime = LocalDateTime.of(2019, 10, 1, 8, 8, 8);System.out.println("当前精确时间:" + ofTime);LocalDate localDate = LocalDate.of(2019, 10, 01);System.out.println("当前日期:" + localDate);LocalTime localTime = LocalTime.of(12, 01, 01);System.out.println("当天时间:" + localTime);}
}
stream
数据源获取方法 | 数据处理方法 | 结果处理方法 |
---|---|---|
Collection.stream () :从集合获取流 Collection.parallelStream () :从集合获取并行流。 Arrays.stream (T array) or Stream.of () :从数组获取流。 BufferedReader.lines () :从输入流中获取流。 IntStream.of () :从静态方法中获取流。 Stream.generate () :自己生成流 | map (mapToInt , flatMap 等)、 filter 、 distinct 、 sorted 、 peek 、 limit 、 skip 、 parallel 、 sequential 、 unordered | forEach 、forEachOrdered 、toArray 、reduce 、collect 、min 、max 、count 、anyMatch 、allMatch 、noneMatch 、findFirst 、findAny 、iterator |
先看一个最简单的示例
private static void generateHandle() {// 不使用流操作List<String> names = Arrays.asList("A", "BBBB", "CCCC", "D");// 筛选出长度为4的名字List<String> subList = new ArrayList<>();for (String name : names) {if (name.length() == 4) {subList.add(name);}}// 把值用逗号分隔StringBuilder sbNames = new StringBuilder();for (int i = 0; i < subList.size() - 1; i++) {sbNames.append(subList.get(i));sbNames.append(", ");}// 去掉最后一个逗号if (subList.size() > 1) {sbNames.append(subList.get(subList.size() - 1));}System.out.println(sbNames);}
用stream
来做,就简洁很多
private static void useStream() {List<String> names = Arrays.asList("A", "BBBB", "CCCC", "D");String nameString = names.stream().filter(num -> num.length() == 4).collect(Collectors.joining(", "));System.out.println(nameString);}
package git.snippets.jdk8;import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** stream使用* 数据源(source) -> 数据处理 / 转换(intermedia) -> 结果处理(terminal )* @author <a href="mailto:410486047@qq.com">Grey</a>* @date 2021/11/21* @since 1.8*/
public class StreamTest {static void demo1() {List<String> nameList = Arrays.asList("A", "B", "AASDSD", "ABCD");nameList.stream().filter(name -> name.length() == 4).map(name -> "This is " + name).forEach(System.out::println);}static void mathTest() {List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);IntSummaryStatistics stats = list.stream().mapToInt(x -> x).summaryStatistics();System.out.println("最小值:" + stats.getMin());System.out.println("最大值:" + stats.getMax());System.out.println("个数:" + stats.getCount());System.out.println("和:" + stats.getSum());System.out.println("平均数:" + stats.getAverage());}static void groupByTest() {List<Integer> ageList = Arrays.asList(11, 22, 13, 14, 25, 26);Map<String, List<Integer>> groupMap = ageList.stream().collect(Collectors.groupingBy(age -> String.valueOf(age / 10)));groupMap.forEach((k, v) -> {System.out.println("年龄" + k + "0多岁的有:" + v);});}static void partitioningByTest() {List<Integer> ageList = Arrays.asList(11, 22, 13, 14, 25, 26);Map<Boolean, List<Integer>> ageMap = ageList.stream().collect(Collectors.partitioningBy(age -> age > 18));System.out.println("未成年人:" + ageMap.get(false));System.out.println("成年人:" + ageMap.get(true));}static void generateTest() {// 生成自己的随机数流Random random = new Random();Stream<Integer> generateRandom = Stream.generate(random::nextInt);generateRandom.limit(5).forEach(System.out::println);// 生成自己的 UUID 流Stream<UUID> generate = Stream.generate(UUID::randomUUID);generate.limit(5).forEach(System.out::println);}
}
函数式接口
有且仅有一个抽象方法的接口就是函数式接口。可以通过
@FunctionalInterface
标识,对于只有单个抽象方法(single abstract method)的接口,需要这种接口的对象时,就可以提供Lambda表达式。
最简单的一个函数式接口示例:
@FunctionalInterface
public interface FunctionDemo {void say(String name, int age);default void hi(String name, int age) {say(name, age);}
}
package git.snippets.jdk8;public class FunctionInterfaceDemo {public static void main(String[] args) {function0();}// 最简单的函数式接口static void function0() {FunctionDemo demo = (name, age) -> System.out.println("我叫" + name + "我今年" + age + "岁");demo.say("zhangsan", 20);demo.hi("zhanshang", 20);}
}
Predicate
可以过滤出满足条件的特定元素
示例:
package git.snippets.jdk8;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;/*** @author <a href="mailto:410486047@qq.com">Grey</a>* @date 2021/11/24* @since 1.8*/
public class PredicateTest {public static void main(String[] args) {List<Integer> numberList = Arrays.asList(3, 4, 5, 6, 7, 8, 9, 10);Predicate<Integer> lessThan5 = number -> number <= 5;Predicate<Integer> greaterThan9 = number -> number >= 9;// 小于等于 5System.out.println(filter(numberList, lessThan5));// 大于 5System.out.println(filter(numberList, lessThan5.negate()));// 小于等于 5 或者大于等于 9System.out.println(filter(numberList, lessThan5.or(greaterThan9)));// ! (小于等于 5 AND 大于等于 9)System.out.println(filter(numberList, lessThan5.and(greaterThan9).negate()));}// 过滤出满足条件(条件可以自定义)的特定集合元素private static <T> List<T> filter(List<T> numberList, Predicate<T> p) {List<T> result = new ArrayList<>();for (T t : numberList) {if (p.test(t)) {result.add(t);}}return result;}
}
Consumer
Consumer
有如下类型
类型 | 作用 |
---|---|
BiConsumer | 传入两个任意类型参数,无返回值 |
DoubleConsumer | 传入一个 double 参数,无返回值 |
IntConsumer | 传入一个 int 参数,无返回值 |
LongConsumer | 传入一个 long 参数,无返回值 |
ObjDoubleConsumer | 传入一个任意类型参数,一个 double 参数,无返回值 |
ObjIntConsumer | 传入一个任意类型参数,一个 int 参数,无返回值 |
ObjLongConsumer | 传入一个任意类型参数,一个 long 参数,无返回值 |
示例代码
package git.snippets.jdk8;import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.ObjIntConsumer;/*** Consumer测试* <p>* BiConsumer 传入两个任意类型参数,无返回值* <p>* DoubleConsumer 传入一个 double 参数,无返回值* <p>* IntConsumer 传入一个 int 参数,无返回值* <p>* LongConsumer 传入一个 long 参数,无返回值* <p>* ObjDoubleConsumer 传入一个任意类型参数,一个 double 参数,无返回值* <p>* ObjIntConsumer 传入一个任意类型参数,一个 int 参数,无返回值* <p>* ObjLongConsumer 传入一个任意类型参数,一个 long 参数,无返回值** @author <a href="mailto:410486047@qq.com">Grey</a>* @date 2021/11/26* @since 1.8*/
public class ConsumerTest {public static void main(String[] args) {t1();t2();t3();t4();}// 多个Consumer结合使用static void t1() {Consumer<String> c = System.out::println;Consumer<String> len = s -> System.out.print(s.length());len.andThen(c).accept("hello");}private static void t4() {List<String> list = Arrays.asList("ab", "abcd");// 某个字符串串的长度大于给定的value值,就打印list.forEach(s -> {if (s.length() > 3) {System.out.println(s);}});}// 打印map中的value满足条件的key值private static void t3() {Map<String, Integer> map = new HashMap<>();map.put("zhangshang", 17);map.put("list", 21);map.put("wangwu", 18);BiConsumer<String, Integer> consumer = (s, i) -> {// value大于18的记录,打印其value值if (i > 18) {System.out.println(s);}};map.forEach(consumer);}private static void t2() {List<String> list = Arrays.asList("ab", "cd");// 打印字符串list.forEach(System.out::println);// 打印每个字符串的长度list.forEach(s -> System.out.println(s.length()));}
}
Supplier
Supplier
是一个功能接口,代表结果的提供者。Supplier
的功能方法是get()。一个Supplier
可以通过lambda
表达式、方法引用或默认构造函数来实例化。
示例代码如下
private static void s1() throws InterruptedException {// 定义一个Supplier,可以生成区间为[0,10)的随机数Supplier<Integer> supplier = () -> new Random().nextInt(10);System.out.println(supplier.get());System.out.println(supplier.get());// 获取当前时间Supplier<LocalDateTime> s2 = LocalDateTime::now;System.out.println(s2.get());Thread.sleep(1000);System.out.println(s2.get());}
此外,使用Supplier
,还可以优雅实现工厂模式,见
package git.snippets.jdk8;import java.time.LocalDateTime;
import java.util.Random;
import java.util.UUID;
import java.util.function.Supplier;/*** Supplier使用** @author <a href="mailto:410486047@qq.com">Grey</a>* @date 2021/11/27* @since*/
public class SupplierTest {public static void main(String[] args) throws InterruptedException {System.out.println(factory(() -> new Sharp("abc")));}// supplier实现工厂模式static Sharp factory(Supplier<? extends Sharp> supplier) {Sharp sharp = supplier.get();sharp.name = sharp.name + UUID.randomUUID();return sharp;}
}class Sharp {String name;Sharp(String name) {this.name = name;}@Overridepublic String toString() {return "Sharp{" + "name='" + name + '\'' + '}';}
}
UnaryOperator
UnaryOperator
接受一个参数并返回与其输入参数相同类型的结果。
示例代码
package git.snippets.jdk8;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;/*** UnaryOperator使用** @author <a href="mailto:410486047@qq.com">Grey</a>* @date 2021/11/28* @see UnaryOperator* @since 1.8*/
public class UnaryOperatorTest {public static void main(String[] args) {List<String> list = Arrays.asList("abcddd", "12233243");// 将List元素先转大写,然后截取前3位,最后打印出来mapAndConsumer(list, System.out::println, String::toUpperCase, s -> s.substring(0, 3));unaryOperator2();}// 接收多个`UnaryOperator`对List元素进行处理,得到的结果执行传入consumer中public static <T> void mapAndConsumer(List<T> list, Consumer<T> consumer, UnaryOperator<T>... unaryOperator) {for (T t : list) {for (UnaryOperator<T> operator : unaryOperator) {t = operator.apply(t);}consumer.accept(t);}}static void unaryOperator2() {Function<String, String> upperFun1 = String::toUpperCase;UnaryOperator<String> upperFun2 = String::toUpperCase;List<String> list = Arrays.asList("abc", "efg");// Function.identity() 和 UnaryOperator.identity()都不对结果进行任何操作Map<String, String> map1 = list.stream().collect(Collectors.toMap(upperFun1, Function.identity()));Map<String, String> map2 = list.stream().collect(Collectors.toMap(upperFun2, UnaryOperator.identity()));Map<String, String> map3 = list.stream().collect(Collectors.toMap(upperFun2, t -> t));System.out.println(map1);System.out.println(map2);System.out.println(map3);}
}
惰性计算
package git.snippets.jdk8;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** 惰性计算** @author <a href="mailto:410486047@qq.com">Grey</a>* @date 2021/11/23* @since 1.8*/
public class LazyTest {public static void main(String[] args) {lazyTest();}private static void lazyTest() {List<Integer> numberLIst = Arrays.asList(1, 2, 3, 4, 5, 6);// 找出偶数Stream<Integer> integerStream = numberLIst.stream().filter(number -> {int temp = number % 2;if (temp == 0) {System.out.println(number);}return temp == 0;});System.out.println("分割线");// 到这里才调用List<Integer> collect = integerStream.collect(Collectors.toList());}
}
如上代码,打印的结果是:
分割线
2
4
6
说明调用filter
的过程是在integerStream.collect(Collectors.toList());
执行才触发,这就是惰性计算。
JUC 包中的 CompletableFuture
其中的
anyOf()
可以实现“任意个CompletableFuture
只要一个成功”,allOf()
可以实现“所有CompletableFuture都必须成功”,这些组合操作可以实现非常复杂的异步流程控制。
用法参考如下代码
package git.snippets.juc;import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;/*** 假设你能够提供一个服务* 这个服务查询各大电商网站同一类产品的价格并汇总展示*/
public class CompletableFutureUsage {public static void main(String[] args) throws ExecutionException, InterruptedException {way1();way2();}public static void way1() {long start = System.currentTimeMillis();System.out.println("p1 " + priceOfJD());System.out.println("p2 " + priceOfTB());System.out.println("p3 " + priceOfTM());long end = System.currentTimeMillis();System.out.println("串行执行,耗时(ms):" + (end - start));}public static void way2() throws ExecutionException, InterruptedException {long start = System.currentTimeMillis();CompletableFuture<Double> p1 = CompletableFuture.supplyAsync(() -> priceOfJD());CompletableFuture<Double> p2 = CompletableFuture.supplyAsync(() -> priceOfTB());CompletableFuture<Double> p3 = CompletableFuture.supplyAsync(() -> priceOfTM());CompletableFuture.allOf(p1, p2, p3).join();System.out.println("p1 " + p1.get());System.out.println("p2 " + p2.get());System.out.println("p3 " + p3.get());long end = System.currentTimeMillis();System.out.println("使用CompletableFuture并行执行,耗时(ms): " + (end - start));}private static double priceOfTM() {delay();return 1.00;}private static double priceOfTB() {delay();return 2.00;}private static double priceOfJD() {delay();return 3.00;}/*private static double priceOfAmazon() {delay();throw new RuntimeException("product not exist!");}*/private static void delay() {int time = new Random().nextInt(500);try {TimeUnit.MILLISECONDS.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}// System.out.printf("After %s sleep!\n", time);}
}
JUC 包中的 WorkStealingPool
每个线程都有单独的队列,每个线程队列执行完毕后,就会去其他的线程队列里面拿过来执行, 底层是:ForkJoinPool,会自动启动cpu核数个线程去执行任务
示例代码
package git.snippets.juc;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class WorkStealingPoolUsage {public static void main(String[] args) throws IOException {int core = Runtime.getRuntime().availableProcessors();// 会自动启动cpu核数个线程去执行任务 ,其中第一个是1s执行完毕,其余都是2s执行完毕,// 有一个任务会进行等待,当第一个执行完毕后,会再次偷取最后一个任务执行ExecutorService service = Executors.newWorkStealingPool();service.execute(new R(1000));for (int i = 0; i < core; i++) {service.execute(new R(2000));}//由于产生的是精灵线程(守护线程、后台线程),主线程不阻塞的话,看不到输出System.in.read();}static class R implements Runnable {int time;R(int t) {this.time = t;}@Overridepublic void run() {try {TimeUnit.MILLISECONDS.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(time + " " + Thread.currentThread().getName());}}
}
更多
Java SE 7及以后各版本新增特性,持续更新中…
参考资料
Java 新特性教程
Java Language Updates
Enhancements in Java SE 8
New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in Java SE 8
Java多线程学习笔记
Spring in Action, 5th
Java核心技术·卷 I(原书第11版)
Java核心技术·卷 II(原书第11版)