当前位置:网站首页>Optional classes, convenience functions, creating options, optional object operations, and optional streams

Optional classes, convenience functions, creating options, optional object operations, and optional streams

2022-06-21 09:36:00 tragically unhappy

Preface

We must consider what happens when we get elements in an empty stream , We are always used to the fact that the flow is uninterrupted . However , Place... In the stream null But it can be easily interrupted , So can there be an object , This allows us to hold the stream elements while , You can also give us friendly hints when the element does not exist ( No exceptions )

One 、 Optional class

Optional Can achieve such a function . Some of the standard stream operations can return Optional object , Because they don't guarantee the expected results .

  • findFirst(): Returns the... Containing the first element Optional object , If the stream is empty, return Optional.empty.
  • findAny(): Returns... Containing any element Optional object , If the stream is empty, return Optional.empty.
  • max() and min(): Returns a value containing the maximum or minimum value Optional object , If the stream is empty, return Optional.empty.

reduce() No more with identity Form begins , Instead, include its return value in Optional in .(identity Objects become other forms of reduce() The default result of , So there is no risk of an empty result ) For digital streams IntStream etc. ,average() The results will be packaged in Optional To prevent the flow from being empty .

public class OptionalsFromEmptyStreams {
    
    public static void main(String[] args) {
    
        System.out.println(Stream.<String>empty()
                .findFirst());
        System.out.println(Stream.<String>empty()
                .findAny());
        System.out.println(Stream.<String>empty()
                .max(String.CASE_INSENSITIVE_ORDER));
        System.out.println(Stream.<String>empty()
                .min(String.CASE_INSENSITIVE_ORDER));
        System.out.println(Stream.<String>empty()
                .reduce((s1, s2) -> s1 + s2));
        System.out.println(IntStream.empty()
                .average());
    }
}
/* output: Optional.empty Optional.empty Optional.empty Optional.empty Optional.empty OptionalDouble.empty */

When the stream is empty, you get a Optional.empty object , Instead of throwing an exception .Optional Have toString() Methods can be used to present useful information .
Be careful : Air flow is through Stream.<String>empty() Created . If you call... Without any context Stream.empty(),Java Don't know its data type .

Here is Optional The basic usage of :

public class OptionalBasics {
    
    static void test(Optional<String> optString) {
    
        if (optString.isPresent())
            System.out.println(optString.get());
        else
            System.out.println("Nothing inside!");
    }

    public static void main(String[] args) {
    
        test(Stream.of("Epithets").findFirst());
        test(Stream.<String>empty().findFirst());
    }
}
/* output: Epithets Nothing inside! */

When you receive Optional Object time , Should be First call isPresent() Check if it contains elements , If there is , You can use get() obtain .

Two 、 Convenience functions

There are many convenience functions to unpack Optional ,

  • isPresent(Consumer): Call when the value exists Consumer, Otherwise, do nothing .
  • orElse(otherObject): If the value exists, it will return , Otherwise it generates otherObject.
  • orElseGet(Supplier): If only exists, it will directly return , Otherwise use Supplier Function to generate an alternative object .
  • orElseThrow(Supplier): If the value exists, return , Otherwise use Supplier Function generates an exception .
public class Optionals {
    
    static void basics(Optional<String> optString) {
    
        if (optString.isPresent()) {
    
            System.out.println(optString.get());
        } else System.out.println("Nothing Inside!");
    }

    static void ifPresent(Optional<String> optString) {
    
        optString.ifPresent(System.out::println);
    }

    static void orElse(Optional<String> optString) {
    
        System.out.println(optString.orElse("Nada"));
    }

    static void orElseGet(Optional<String> optString) {
    
        System.out.println(optString.orElseGet(() -> "Generated"));
    }

    static void orElseThrow(Optional<String> optString) {
    
        try {
    
            System.out.println(optString.orElseThrow(() -> new Exception("Supplied")));
        } catch (Exception e) {
    
            System.out.println("Caught " + e);
        }
    }

    static void test(String testName, Consumer<Optional<String>> cos) {
    
        System.out.println("===" + testName + "=====");
        cos.accept(Stream.of("Epithets").findFirst());
        cos.accept(Stream.<String>empty().findFirst());
    }

    public static void main(String[] args) {
    
        test("basics", Optionals::basics);
        test("ifPresent", Optionals::ifPresent);
        test("orElse", Optionals::orElse);
        test("orElseGet", Optionals::orElseGet);
        test("orElseThrow", Optionals::orElseThrow);
    }
}
/* output: ===basics===== Epithets Nothing Inside! ===ifPresent===== Epithets ===orElse===== Epithets Nada ===orElseGet===== Epithets Generated ===orElseThrow===== Epithets Caught java.lang.Exception: Supplied */

3、 ... and 、 establish Optional

When we add Optional when , You can use the following three static methods :

  • empty(): Generate an empty Optional.
  • of(value): Wrap a non null value to Optional in .
  • ofNullable(): For a value that may be empty , Automatically generated for space time Optional.empty, Otherwise, wrap the value in Optional in .

Here is an example :

public class CreatingOptionals {
    
    static void test(String testName, Optional<String> optional) {
    
        System.out.println("====" + testName + "====");
        System.out.println(optional.orElse("NULL"));
    }

    public static void main(String[] args) {
    
        test("empty", Optional.empty());
        test("of", Optional.of("Howdy()"));
        try {
    
            test("of", Optional.of(null));
        } catch (Exception e) {
    
            System.out.println(e);
        }

        test("ofNullable", Optional.ofNullable("Hi"));
        test("ofNullable", Optional.ofNullable(null));
    }
}
/* output: ====empty==== NULL ====of==== Howdy() java.lang.NullPointerException ====ofNullable==== Hi ====ofNullable==== NULL */

We can't pass null To of() To create Optional object , The safest way is : Use ofNullable() To handle it gracefully null.

Four 、 Optional The object operation :filter、map、flatMap

When our flow pipe produces Optional object , The following three methods can make Optional The follow-up can do more operations :

  • filter(Predicate): Yes Optional Content application in Predicate And return the result . If Optional dissatisfaction Predicate , take Optional Turn to empty Optional. If Optional It's empty , Then return to null directly Optional.
  • map(Function): If Optional Not empty , application Function On Optional The content in , And return the result . Otherwise go straight back to Optional.empty.
  • flatMap(Function): Same as map(), But the provided mapping function ( Namely Function) Wrap the results in Optional In the object , therefore flatMap() No packaging at the end .
public class OptionalFilter {
    
    static String[] elements = {
    "Foo", "Bar", "Baz", "Bingo"};
    static Stream<String> testStream() {
    
        return Arrays.stream(elements);
    }

    static void test(String descr, Predicate<String> predicate) {
    
        System.out.println("---(" + descr + ")----");
        for (int i = 0; i <= elements.length; i++) {
    
            System.out.println(testStream()
                    .skip(i)
                    .findFirst()
                    .filter(predicate));
        }
    }

    public static void main(String[] args) {
    
        test("true", s -> true);
        test("false", s -> false);
        test("s != \"\"", s -> s != "");
        // Here s.length()  Is an incoming single stream element 
        test("s.length() == 3", s -> s.length() == 3);
        test("startsWith(\"B\")", s -> s.startsWith("B"));
    }
}
/* output: ---(true)---- Optional[Foo] Optional[Bar] Optional[Baz] Optional[Bingo] Optional.empty ---(false)---- Optional.empty Optional.empty Optional.empty Optional.empty Optional.empty ---(s != "")---- Optional[Foo] Optional[Bar] Optional[Baz] Optional[Bingo] Optional.empty ---(s.length() == 3)---- Optional[Foo] Optional[Bar] Optional[Baz] Optional.empty Optional.empty ---(startsWith("B"))---- Optional.empty Optional[Bar] Optional[Baz] Optional[Bingo] Optional.empty */

Even if the output looks like a stream , Pay special attention to test() Medium for loop :1. Every time for Loops operate on newly generated streams ,2. Skip the specified number of elements ,3. By calling findFirst() Get the first of the remaining elements , And package it in Optional In the object .
Be careful : This is different from ordinary for loop , there be equal to Number actually makes the last bit out of the range of the stream that the array is converted to , But it doesn't go wrong .

Same as map() equally ,Optional.map() Only in the Optional This mapping function is executed only when it is not empty , And will Optional Extract the content of , Passed to the mapping function .

public class OptionalMap {
    
    static String[] elements = {
    "12", "", "23", "45"};
    static Stream<String> stream() {
    
        return Arrays.stream(elements);
    }

    static void test(String descr, Function<String,String> func) {
    
        System.out.println("---(" + descr + ")----");
        for (int i = 0; i <= elements.length; i++) {
    
            System.out.println(stream()
                    .skip(i)
                    .findFirst()// A optional
                    .map(func));
        }
    }

    public static void main(String[] args) {
    
        test("Add brackets", s -> "[" + s + "]");
        test("Increment", s -> {
    
            try {
    
                return Integer.parseInt(s) + 1 + "";
            } catch (Exception e) {
    
                return s;
            }
        });
        test("Replace", s -> s.replace("2", "9"));
        // Remember every s Is a single flow element 
        test("Take last digit", s -> s.length() > 0 ? s.charAt(s.length() - 1) + "" : s);
    }
}
/* output: ---(Add brackets)---- Optional[[12]] Optional[[]] Optional[[23]] Optional[[45]] Optional.empty ---(Increment)---- Optional[13] Optional[] Optional[24] Optional[46] Optional.empty ---(Replace)---- Optional[19] Optional[] Optional[93] Optional[45] Optional.empty ---(Take last digit)---- Optional[2] Optional[] Optional[3] Optional[5] Optional.empty */

The return result of the mapping function is automatically packaged as Optional.Optional.empty() ( empty ) It will be skipped directly .

public class OptionalFlatMap {
    
    static String[] elements = {
    "12","", "23", "45"};

    static Stream<String> stream() {
    
        return Arrays.stream(elements);
    }

    static void test(String descr, Function<String, Optional<String>> func) {
    
        System.out.println("---(" + descr + ")----");
        for (int i = 0; i <= elements.length; i++) {
    
            System.out.println(stream()
                    .skip(i)
                    .findFirst()
                    .flatMap(func));// The parameter here becomes Optional type 
        }
    }

    public static void main(String[] args) {
    
        test("Add brackets", new Function<String, Optional<String>>() {
    
            @Override
            public Optional<String> apply(String s) {
    
                return Optional.of("[" + s + "]");
            }
        });
        test("Increment",s -> {
    
            try {
    
                return Optional.of(Integer.parseInt(s) + 1 + "");
            } catch (Exception e) {
    
                return Optional.of(s);
            }
        });
        test("Replace", s -> Optional.ofNullable(s.replace("2", "9")));
        test("Take last digit",s->Optional.of(s.length()>0?s.charAt(s.length()-1)+"":s));
    }
}
/* output: ---(Add brackets)---- Optional[[12]] Optional[[]] Optional[[23]] Optional[[45]] Optional.empty ---(Increment)---- Optional[13] Optional[] Optional[24] Optional[46] Optional.empty ---(Replace)---- Optional[19] Optional[] Optional[93] Optional[45] Optional.empty ---(Take last digit)---- Optional[2] Optional[] Optional[3] Optional[5] Optional.empty */

Optional Of flatMap() Apply to generated Optional The mapping function of , So it won't be like map() That encapsulates the results in Optional in .
Same as map(),flatMap() Non empty... Will be extracted Optional Content applies it to mapping functions . The only difference is that it no longer wraps the results in Optional in , Because it has been packed .

5、 ... and 、 Optional flow

Suppose your generator might produce null value . So when you use it to create a stream , use Optional It's better to wrap the elements .

public class Signal {
    
    private final String msg;

    public Signal(String msg) {
    
        this.msg = msg;
    }

    public String getMsg() {
    
        return msg;
    }

    @Override
    public String toString() {
    
        return "Signal{" +
                "msg='" + msg + '\'' +
                '}';
    }

    static Random rand = new Random(47);
    public static Signal morse() {
    
        switch (rand.nextInt(4)) {
    
            case 1:
                return new Signal("dot");
            case 2:
                return new Signal("dash");
            default:
                return null;
        }
    }

    public static Stream<Optional<Signal>> stream() {
    
        return Stream.generate(Signal::morse)
                .map(signal -> Optional.ofNullable(signal));
    }
}

When we use this stream , You have to figure out how to unpack Optional . The code is as follows :

public class StreamOfOptionals {
    
    public static void main(String[] args) {
    
        Signal.stream()
                .limit(10)
                .forEach(System.out::println);
        System.out.println("-----------");
        Signal.stream()
                .limit(10)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .forEach(System.out::println);
    }
}
/* output: Optional[Signal{msg='dash'}] Optional[Signal{msg='dot'}] Optional[Signal{msg='dash'}] Optional.empty Optional.empty Optional[Signal{msg='dash'}] Optional.empty Optional[Signal{msg='dot'}] Optional[Signal{msg='dash'}] Optional[Signal{msg='dash'}] ----------- Signal{msg='dot'} Signal{msg='dot'} Signal{msg='dash'} Signal{msg='dash'} */

Here we use filter() To keep those non empty Optional, And then in map() Use in get() Get elements . Because every situation needs to be defined “ Null value ” The meaning of , So we usually take a different approach for each application .

原网站

版权声明
本文为[tragically unhappy]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/172/202206210928213384.html