введение
В начале статьи давайте сначала поговорим о проблеме NPE.Проблема NPE — исключение NullPointerException, с которым мы часто сталкиваемся при разработке.Предположим, у нас есть два класса, их диаграмма классов UML показана ниже.
В этом случае есть такой код
user.getAddress().getProvince();
скопировать код
Этот способ написания, когда пользователь нулевой, может сообщить об исключении NullPointerException. Для решения этой задачи используется следующий способ записи
if(user!=null){
Address address = user.getAddress();
if(address!=null){
String province = address.getProvince();
}
}
скопировать код
Этот способ написания уродлив Чтобы избежать вышеупомянутого уродливого способа письма, уродливый дизайн становится элегантным. JAVA8 предоставляет необязательный класс для оптимизации этого метода записи, который будет подробно объяснен в следующей текстовой части.
Введение в API
Давайте сначала представим API, В отличие от других статей, эта статья использует аналогию и объединяет исходный код. В отличие от других статей, API перечислены один за другим, из-за чего люди не могут найти суть.
(1)Optional(T value),empty(),of(T value),ofNullable(T value)
Между этими четырьмя функциями существует корреляция, поэтому они объединены в группу для запоминания.
Позвольте мне сначала объяснить, Необязательный (значение T), то есть конструктор, который является закрытым и не может быть вызван извне. Оставшиеся три функции являются общедоступными разрешениями для вызова. Тогда суть Optional заключается в том, что он хранит внутри реальное значение, а при построении напрямую определяет, пусто ли его значение. Ну, это все еще немного абстрактно. Перейдите непосредственно к исходному коду конструктора Optional(T value), как показано на следующем рисунке.
Так,of(T value) исходный кодследующим образом
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
скопировать код
То есть конструктор вызывается внутри функции of(T value). По исходному коду конструктора можем получитьдва вывода:
(1) Необязательный объект, созданный функцией of(T value), по-прежнему будет сообщать об исключении NullPointerException, когда значение Value пусто.
(2) Необязательный объект, созданный функцией of(T value), может нормально создавать необязательный объект, когда значение Value не является пустым.
Кроме того, необязательный класс также поддерживает объект, значение которого равно нулю, что, вероятно, выглядит следующим образом.
public final class Optional<T> {
//省略....
private static final Optional<?> EMPTY = new Optional<>();
private Optional() {
this.value = null;
}
//省略...
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
}
скопировать код
Так,Роль пустого()Это вернуть ПУСТОЙ объект.
Ну, так сказать, так много было проложеноofNullable(T value)Это работает, перейдите к исходному коду
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
скопировать код
Что ж, все должны понимать, что это значит. по сравнению с of (значение T)разницаТо есть, когда значение равно null, of(значение T) сообщит об исключении NullPointerException; ofNullable(значение T) не вызовет исключение, а ofNullable(значение T) напрямую вернет ПУСТОЙ объект.
Означает ли это, что мы используем только функцию ofNullable вместо функции of в проекте?
Нет, вещь существует настолько естественно, что имеет ценность существования. Мы не хотим скрывать исключение NullPointerException во время работы. Вместо этого сообщите об этом немедленно, и в этом случае используется функция Of. Но я должен признать, что такие сцены действительно редки. Блогер использовал эту функцию только при написании тестовых случаев junit.
(2) orElse(T другое), orElseGet(Supplier расширяет T> другое) и orElseThrow(Supplier расширяет X> exceptionSupplier)
Эти три функции сгруппированы вместе для памяти, и все они вызываются, когда значение, переданное конструктором, равно null. Использование orElse и orElseGet выглядит следующим образом, что эквивалентно заданию значения по умолчанию, когда значение равно null:
@Test
public void test() {
User user = null;
user = Optional.ofNullable(user).orElse(createUser());
user = Optional.ofNullable(user).orElseGet(() -> createUser());
}
public User createUser(){
User user = new User();
user.setName("zhangsan");
return user;
}
скопировать код
из этих двух функцийразница:Когда пользовательское значение не равно нулю, функция orElse по-прежнему будет выполнять метод createUser(), а функция orElseGet не будет выполнять метод createUser(), вы можете проверить это самостоятельно.
Что касается orElseThrow, когда значение равно null, сразу создается исключение.
User user = null;
Optional.ofNullable(user).orElseThrow(()->new Exception("用户不存在"));
скопировать код
(3) map(Function super T, ? extends U> mapper) и flatMap(Function super T, Optional> mapper)
Эти две функции помещаются в набор памяти, и эти две функции выполняют преобразование значения. Перейти непосредственно к исходному коду
public final class Optional<T> {
//省略....
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));
}
}
//省略...
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));
}
}
}
скопировать код
Между двумя функциями в теле функции нет никакой разницы.единственная разницаТип входного параметра, принимаемый функцией карты, — это Function, а тип входного параметра лоскутаMap — Function>.
В конкретном использовании,Для карты:
Если структура пользователя выглядит следующим образом
public class User {
private String name;
public String getName() {
return name;
}
}
скопировать код
В это время имя пишется следующим образом
String city = Optional.ofNullable(user).map(u-> u.getName()).get();
скопировать код
Для плоской карты:
Если структура пользователя выглядит следующим образом
public class User {
private String name;
public Optional<String> getName() {
return Optional.ofNullable(name);
}
}
скопировать код
В это время имя пишется следующим образом
String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();
скопировать код
(4) isPresent() и ifPresent(Consumer super T> потребитель)
Эти две функции запоминаются вместе: isPresent определяет, является ли значение пустым, а ifPresent выполняет некоторые операции, когда значение не является пустым. Исходный код этих двух функций выглядит следующим образом
public final class Optional<T> {
//省略....
public boolean isPresent() {
return value != null;
}
//省略...
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
}
скопировать код
Следует отметить, что, пожалуйста, не используйте
if (user != null){
// TODO: do something
}
скопировать код
написать
User user = Optional.ofNullable(user);
if (Optional.isPresent()){
// TODO: do something
}
скопировать код
Из-за этого написания структура кода все еще уродлива. Блогер даст правильное написание позже. Что касается ifPresent(Consumer super T> Consumer), использование также очень простое, как показано ниже.
Optional.ofNullable(user).ifPresent(u->{
// TODO: do something
});
скопировать код
(5) filter(Predicate<? super T> predicate)
Нечего сказать, сразу к исходному коду
public final class Optional<T> {
//省略....
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
скопировать код
Метод фильтра принимает предикат для фильтрации значений, содержащихся в необязательном.Если содержащиеся значения удовлетворяют условиям, возвращается необязательный, в противном случае возвращается необязательный.пустой. Использование заключается в следующем
Optional<User> user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);
скопировать код
Как показано выше, если длина имени пользователя меньше 6, оно будет возвращено. Если оно больше 6, возвращается ПУСТОЙ объект.
реальное боевое применение
Пример 1
в функциональном методе
предыдущее написание
public String getCity(User user) throws Exception{
if(user!=null){
if(user.getAddress()!=null){
Address address = user.getAddress();
if(address.getCity()!=null){
return address.getCity();
}
}
}
throw new Excpetion("取值错误");
}
скопировать код
JAVA8 запись
public String getCity(User user) throws Exception{
return Optional.ofNullable(user)
.map(u-> u.getAddress())
.map(a->a.getCity())
.orElseThrow(()->new Exception("取指错误"));
}
скопировать код
Пример 2
Например, в основной программе
предыдущее написание
if(user!=null){
dosomething(user);
}
скопировать код
JAVA8 запись
Optional.ofNullable(user)
.ifPresent(u->{
dosomething(u);
});
скопировать код
Пример 3
предыдущее написание
public User getUser(User user) throws Exception{
if(user!=null){
String name = user.getName();
if("zhangsan".equals(name)){
return user;
}
}else{
user = new User();
user.setName("zhangsan");
return user;
}
}
скопировать код
java8 письмо
public User getUser(User user) {
return Optional.ofNullable(user)
.filter(u->"zhangsan".equals(u.getName()))
.orElseGet(()-> {
User user1 = new User();
user1.setName("zhangsan");
return user1;
});
}
скопировать код
Другие примеры не перечислены один за другим. Однако блогер считает, что это цепное программирование действительно используется, хотя код и изящный. Однако логика не столь очевидна, а читабельность снижается, так что вы можете использовать ее по мере необходимости в своем проекте.
Автор: Lonely Smoke Источник: http://rjzheng.cnblogs.com/Авторские права на эту статью принадлежат автору и блог-саду.Вы можете перепечатать ее, но это заявление должно быть сохранено без согласия автора, а ссылка на исходный текст должна быть дана в видном месте на странице статьи. , в противном случае сохраняется право на юридическую ответственность. Если вы считаете это полезным, вы можете нажать кнопку【рекомендовать】.