foojay.io
Open in
urlscan Pro
2606:4700::6812:1eaf
Public Scan
Submitted URL: https://go.jetbrains.com/NDI2LVFWRC0xMTQAAAGHPLP_lIb6fS611paa3L-C74j6yPgYDGMBrdXDj3MZOtPJlBC6cwtAn2O14zdReAI4xeX6Ofs=
Effective URL: https://foojay.io/today/use-pattern-matching-to-simplify-java/?mkt_tok=NDI2LVFWRC0xMTQAAAGHPLP_lNiFSLBApIVMT0rhNUF...
Submission: On October 06 via api from BE — Scanned from DE
Effective URL: https://foojay.io/today/use-pattern-matching-to-simplify-java/?mkt_tok=NDI2LVFWRC0xMTQAAAGHPLP_lNiFSLBApIVMT0rhNUF...
Submission: On October 06 via api from BE — Scanned from DE
Form analysis
3 forms found in the DOMGET https://foojay.io/
<form autocomplete="off" role="search" method="get" action="https://foojay.io/">
<div class="search-box__input-wrapper search-input-wrapper">
<input id="searchInput" type="text" placeholder="Search..." value="" name="s">
<label for="searchInput" class="search-input-wrapper__before-icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" stroke="#fff" stroke-linejoin="round" xmlns:v="https://vecta.io/nano">
<path d="M7.333 12.667c2.946 0 5.333-2.388 5.333-5.333S10.28 2 7.333 2 2 4.388 2 7.333s2.388 5.333 5.333 5.333z"></path>
<path d="M14 14l-2.9-2.9" stroke-linecap="round"></path>
</svg></label>
<button type="button" class="search-input-wrapper__clear-btn" style="display: none;"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" opacity=".5" stroke="#fff" stroke-linecap="round" stroke-linejoin="round"
xmlns:v="https://vecta.io/nano">
<path d="M12 4L4 12"></path>
<path d="M4 4l8 8"></path>
</svg></button>
</div>
</form>
POST https://foojay.io/wp-comments-post.php?wpe-comment-post=foojay
<form action="https://foojay.io/wp-comments-post.php?wpe-comment-post=foojay" method="post" id="commentform" class="comment-form">
<p class="comment-notes"><span id="email-notes">Your email address will not be published.</span> <span class="required-field-message" aria-hidden="true">Required fields are marked <span class="required" aria-hidden="true">*</span></span></p>
<div class="form-row">
<label>
<input placeholder="Email" type="email" id="email" name="email" value="" aria-describedby="email-notes">
</label>
</div>
<div class="form-row">
<label>
<input placeholder="Name" type="text" id="author" name="author" value="">
</label>
</div>
<div class="info"><span>Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.</span></div>
<div class="form-row">
<label>
<textarea placeholder="Comment" id="comment" name="comment" aria-required="true" required="required"></textarea>
</label>
</div>
<div class="check__wrapper">
<label class="check__label" for="wp-comment-cookies-consent">
<input class="check__input" id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes">
<span class="check__box"></span>
</label>
<p>Save my name, email, and website in this browser for the next time I comment.</p>
</div>
<p class="form-submit"><button name="submit" type="submit" id="submit" class="btn btn-green btn-submit">Post Comment</button> <input type="hidden" name="comment_post_ID" value="57573" id="comment_post_ID">
<input type="hidden" name="comment_parent" id="comment_parent" value="0">
</p>
<p style="display: none;"><input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="3c4a5f6c23"></p>
<p style="display: none !important;"><label>Δ<textarea name="ak_hp_textarea" cols="45" rows="8" maxlength="100"></textarea></label><input type="hidden" id="ak_js_1" name="ak_js" value="1665016350452">
<script>
document.getElementById("ak_js_1").setAttribute("value", (new Date()).getTime());
</script>
</p>
</form>
GET https://foojay.io/
<form autocomplete="off" role="search" method="get" action="https://foojay.io/">
<label>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z" stroke="white" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M17.5 17.5L13.875 13.875" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
<input placeholder="Search..." type="text" value="" name="s">
</label>
</form>
Text Content
foojay.io Friends of OpenJDK * OpenJDK Hub * Releases OpenJDK Update & Release Details * Java 19 * 19.0.0 – Sept, 2022 * Java 18 * 18.0.2 — July, 2022 * 18.0.1 — April, 2022 * 18.0.0 — March, 2022 * Java 17 * 17.0.4 — July, 2022 * 17.0.3 — Apr, 2022 * 17.0.2 — Jan, 2022 * 17.0.1 — Oct, 2021 * 17.0.0 — Sept, 2021 * Java 15 Java 15 Releases: * 15.0.8 — July, 2022 * 15.0.7 — Apr, 2022 * 15.0.6 — Jan, 2022 * 15.0.5 — Oct, 2021 * 15.0.4 — July, 2021 * 15.0.3 — Apr, 2021 * 15.0.2 — Jan, 2021 * 15.0.1 — Oct, 2021 View All * Java 13 Java 13 Releases: * 13.0.12 — July, 2022 * 13.0.11 — Apr, 2022 * 13.0.10 — Jan, 2022 * 13.0.9 — Oct, 2021 * 13.0.8 — July, 2021 * 13.0.7 — Apr, 2021 * 13.0.6 — Jan, 2021 * 13.0.5/13.0.5.1 — Oct, 2020 View All * Java 11 Java 11 Releases: * 11.0.16 — July, 2022 * 11.0.15 — Apr, 2022 * 11.0.14 — Jan, 2022 * 11.0.13 — Oct, 2021 * 11.0.12 — July, 2021 * 11.0.11 — Apr, 2021 * 11.0.10 — Jan, 2021 * 11.0.9/11.0.9.1 — Oct, 2020 View All * Java 8 Java 8 Releases: * 8u342/345 — July, 2022 * 8u332 — Apr, 2022 * 8u322 — Jan, 2022 * 8u312 — Oct, 2021 * 8u302 — July, 2021 * 8u292 — Apr, 2021 * 8u282 — Jan, 2021 * 8u272/8u275 — Oct, 2020 View All * Java 7 Java 7 Releases: * 7u351 — July, 2022 * 7u342/7u341 — April, 2022 * 7u332/7u331 — Jan, 2022 * 7u251 — Jan, 2020 View All View All * Distros Java Version Almanac * Long-Term Support (LTS): * Java 17 * Java 11 * Java 8 * Java 7 * Medium-Term Support (MTS): * Java 15 * Java 13 * Short-Term Support (STS): * Java 19 * Java 18 * Java 16 * Java 14 * Java 12 * Java 10 * Java 9 * Command Line OpenJDK Command Line Arguments * Java 16 * Java 15 * Java 14 * Java 13 * Java 12 * Java 11 * Java 10 * Java 9 * Java 8 * Java 7 * Java 6 * Terminology OpenJDK Terminology * OpenJDK with Visual C++ * Thread Dump * OpenJDK Coding Guidelines and Code Reviews * Security and Vulnerability Management * jtreg Test Suites * Latency * Download * Community Hub * Foojay Today * Join Foojay on Slack * Demystifying JVM Memory Management May 20, 2021 Deepu K Sasidharan * VS Code: Getting Better and Better for Java May 18, 2021 Yaojin Yang View All * Latest * Opinion * testing * Tutorials Am I Testing the Right Way? David Schneider, Sebastian Konieczek October 04, 2022 Read More * Java Events GIDS Live 2021 * Virtual & Free April 27, 2021 Virtual Tune in for Wurreka's second virtual conference and job event series, GIDS Live 2021, April 27-30. The four-day program includes an eclectic mix of technical talks, conversations and experiences, featuring some of the most talented and influential figures in software ... * Java User Groups * Java Champions * Slack Channel * About * About Foojay * Advisory Board * Download Foojay Today * Java Core USE PATTERN MATCHING TO SIMPLIFY JAVA September 07, 2022 The concept of pattern matching has been around since the 1960s. It’s a well-known language technique used in many programming languages, from Haskell and AWK to Rust and Scala. Pattern matching is relatively new to Java. It was introduced in JDK 14 and has been progressing with new uses since then. This article explores how these new features can make your code more concise without losing readability. If you’re more of an interactive learner, watch my on-demand webinar on pattern matching in Java from June 2022. First, let’s back up and explain what pattern matching is. WHAT IS PATTERN MATCHING? A pattern consists of two distinct things: * A match predicate gives us a way of determining whether we have a target that matches a given pattern. Being a predicate, it evaluates to a Boolean, meaning it matches against the pattern or it doesn’t. * One or more pattern variables is associated with that match predicate. Pattern variables are conditionally extracted based on the evaluation of the predicate. There are several different pattern types that we can use. 1. Constant: This has existed in Java from the beginning. The switch statement uses a constant pattern for each case. Since the pattern predicate matches a value, there is no need for a pattern variable. 2. Type: Since Java is an object-oriented language, we can use a pattern predicate that matches a Java type. This is the pattern that we talk most about in this article. 3. Deconstruction: In this type of pattern matching, not only do we evaluate a predicate, but we also extract values from objects to populate the pattern variables. 4. Var: Like local variable type inference, introduced in JDK 10, this type of pattern matching uses the compiler to infer types for us. 5. Any: Like var, it will match anything; but in this case, we simply ignore the value. This will become clear when we look at an example later. WHY DO WE NEED PATTERN MATCHING? Pattern matching allows us to test for a specific pattern on a character sequence or a data structure. It makes code easier to read, easier to understand, faster to create, and more resistant to bugs. * Pattern matching creates cleaner, shorter code by relying less on reflection and casting. Code expresses more complex logic with fewer lines. * Pattern matching reduces bugs caused by pattern dominance (pattern dominance is when a previous pattern supersedes another, making it unreachable) and pattern non-exhaustiveness (pattern exhaustiveness is when the compiler warns you that you have not checked for all possible variants of a type). THE INSTANCEOF OPERATOR IN JDK 18 Let’s look at how we use the instanceof operator. Because Java is object-oriented, we have polymorphism: we can view an object as any of the types that it is – its exact type, any of the superclasses, and any of the interfaces it implements. Often, we are faced with a situation where we’re provided with a reference, but we are unsure of its specific type. We can test the reference to see if it is a given type using the instanceofoperator. Here’s a simple example: if (o instanceof String) { String s = (String)o; System.out.printin("Length = " + s.length()); } if (o instanceof String) { String s = (String)o; System.out.printin("Length = " + s.length()); } if (o instanceof String) { String s = (String)o; System.out.printin("Length = " + s.length()); } Having determined that the reference o is of type String, we must define a new local variable of type Stringand assign to it the value of o using an explicit cast. Pattern matching for instanceof, a permanent feature since JDK 16, eliminates this unnecessary extra boilerplate code. The code now looks like this: if (o instanceof String s) { System.out.printin("Length = " + s.length()); } if (o instanceof String s) { System.out.printin("Length = " + s.length()); } if (o instanceof String s) { System.out.printin("Length = " + s.length()); } Here, the pattern predicate is whether o is an instanceof String and the pattern variable is s, which is assigned for us by the compiler. Pattern matching for instanceof uses what is called flow scoping. If you look at local variables, their scope runs from where it is declared until the end of the block in which it is declared (method, loop, block, etc.) They are also subject to definite assignment (they must explicitly be assigned a value). In the case of predicate variables, they are also subject to definite assignment, but their scope is the set of places where they would have definite assignment. Taking the example above, the scope of s is only valid inside the true branch of this if statement because that’s the only place it will have definite assignment. There are two things to bear in mind here. 1 – If you invert the test like this, the variable s will have scope until the end of the block containing the if statement: if (!(o instanceof String s)) return; if (!(o instanceof String s)) return; if (!(o instanceof String s)) return; 2 – This allows the reuse of the same variable name, like this: if (o instanceof Float n) { } else if (o instanceof Integer n) { } else if (o instanceof Short n) { } if (o instanceof Float n) { } else if (o instanceof Integer n) { } else if (o instanceof Short n) { } if (o instanceof Float n) { } else if (o instanceof Integer n) { } else if (o instanceof Short n) { } SWITCH STATEMENTS AND EXPRESSIONS IN JDK 18 The next use of pattern matching in Java is in switch. Until JDK 17, even with the introduction of switch expressions, we were still constrained to a small set of types we could switch over: integral values, strings, and enumerations. JDK 17 introduced pattern matching for switch, which allows us to use a type pattern as a case. For example: void typeTester(Object o) { switch (o) { case null -> System.out.printIn("Null type"); case String s -> System.out.printIn("String length: " + s.length()); case Color c -> System.out.printIn("Color with RGB: " + c.getRGB(); case int[] ia -> System.out.printIn("Array of ints, length" + ia.length); default -> System.out.printIn(o.toString()); } } void typeTester(Object o) { switch (o) { case null -> System.out.printIn("Null type"); case String s -> System.out.printIn("String length: " + s.length()); case Color c -> System.out.printIn("Color with RGB: " + c.getRGB(); case int[] ia -> System.out.printIn("Array of ints, length" + ia.length); default -> System.out.printIn(o.toString()); } } void typeTester(Object o) { switch (o) { case null -> System.out.printIn("Null type"); case String s -> System.out.printIn("String length: " + s.length()); case Color c -> System.out.printIn("Color with RGB: " + c.getRGB(); case int[] ia -> System.out.printIn("Array of ints, length" + ia.length); default -> System.out.printIn(o.toString()); } } There are several things to understand here. Both switch statements and switch expressions can now include an explicit null case. This is useful to eliminate the need for a potential explicit test before the switch. To maintain backwards compatibility, if a null case is not included, the compiler will insert one as the first that throws a NullPointerException. Since a null is always a null, there is no need for a pattern variable. It is also possible to include null with the default case: null, default -> System.out.printIn("Invalid type"); null, default -> System.out.printIn("Invalid type"); null, default -> System.out.printIn("Invalid type"); For the String and Color type cases, the pattern predicate matches on those types and assigns the reference to the specified pattern variable if there is a match. The scope of the pattern variables is only in the relevant case block Primitives (like int and float) in Java are not types, so we cannot use them for a pattern predicate. However, an array of primitives is a type and we can therefore have a case for an array of ints. When using pattern matching for switch (either in a statement or expression), the switch must be exhaustive. This means that all possible types must be handled. Let’s take this switch, for example. switch (o) { case integer i -> System.out.printIn("Integer"); case Byte b -> System.out.printIn("Byte"); } switch (o) { case integer i -> System.out.printIn("Integer"); case Byte b -> System.out.printIn("Byte"); } switch (o) { case integer i -> System.out.printIn("Integer"); case Byte b -> System.out.printIn("Byte"); } In this case, if o is of type Float, there is no case to handle it. We could have simply passed over the switch, but that could lead to hard-to-find bugs and is not a good design. The obvious way to resolve this is to include a default case that matches against anything that is not an Integer or Byte. This does not mean, however, that every switch must have a default case to be complete. JDK 15 introduced another new language construct, sealed classes. Here we define a simple sealed type. Public sealed class Shape permits Triangle, Square, Pentagon {...} Public sealed class Shape permits Triangle, Square, Pentagon {...} Public sealed class Shape permits Triangle, Square, Pentagon {...} We could use this in a switch like this: void typeTester(Shape shape) { switch (shape) { case Triangle t -> System.out.println("It's a triangle"); case Square s -> System.out.println("It's a square"); case Pentagon p -> System.out.println("It's a pentagon"); case Shape s -> System.out.println("It's a shape"); } } void typeTester(Shape shape) { switch (shape) { case Triangle t -> System.out.println("It's a triangle"); case Square s -> System.out.println("It's a square"); case Pentagon p -> System.out.println("It's a pentagon"); case Shape s -> System.out.println("It's a shape"); } } void typeTester(Shape shape) { switch (shape) { case Triangle t -> System.out.println("It's a triangle"); case Square s -> System.out.println("It's a square"); case Pentagon p -> System.out.println("It's a pentagon"); case Shape s -> System.out.println("It's a shape"); } } Since Shape can only have subclasses of Triangle, Square and Pentagon, we have covered all possibilities in the switch, and it is exhaustive (this is also referred to as completeness). The order of the patterns is also significant. If we were to make the case for Shape the first one, it would catch all objects. Since this would render the lower cases unreachable, the compiler would generate an error. Pattern matching for switch also includes guarded patterns. In this case, we can add a test to our pattern. Using the above example: void typeTester(Shape shape) { switch (shape) { case Triangle t && t.size() < 25 -> System.out.println("Small triangle"); case Triangle t -> System.out.println("Big triangle"); case Square s -> System.out.println("It's a square"); case Pentagon p -> System.out.println("It's a pentagon"); case Shape s -> System.out.println("It's a shape"); } } void typeTester(Shape shape) { switch (shape) { case Triangle t && t.size() < 25 -> System.out.println("Small triangle"); case Triangle t -> System.out.println("Big triangle"); case Square s -> System.out.println("It's a square"); case Pentagon p -> System.out.println("It's a pentagon"); case Shape s -> System.out.println("It's a shape"); } } void typeTester(Shape shape) { switch (shape) { case Triangle t && t.size() < 25 -> System.out.println("Small triangle"); case Triangle t -> System.out.println("Big triangle"); case Square s -> System.out.println("It's a square"); case Pentagon p -> System.out.println("It's a pentagon"); case Shape s -> System.out.println("It's a shape"); } } The first case for Triangle now includes an additional test (guard) to determine if its size is less than 25. For the switch to remain exhaustive, we must also have a case for Triangle without a guard to handle triangles of size 25 or greater. In JDK 19, the syntax for guarded patterns will change, replacing the && operator with the keyword, when. Similarly, we must put the guarded Triangle case before the unguarded to avoid the guarded one being unreachable. More pattern matching will be added to Java in the future. Already, JDK 19 is scheduled to include pattern matching for records, which is a deconstruction pattern. We’ll cover that and some other aspects in a later blog post. ALL THE READABILITY WITHOUT THE UNNECESSARY CODE As you can see, pattern matching is a powerful addition to the Java language that reduces the amount of boilerplate code required without sacrificing readability. It also provides several ways to help detect errors at compile time rather than at runtime when your code is in production. Why not try using pattern matching in your next Java application? Want to learn more about pattern matching in JDK 18? Watch our on-demand webinar from June 2022, The Art of Java Language Pattern Matching. You will learn some of the newer features in the Java language, plus some ideas that may be included in future versions of Java, all around this idea of pattern Don’t Forget to Share This Post! * * * * Author Simon Ritter RELATED ARTICLES View All * JDK 7: An Extended Hello and Farewell Azul continues to provide updates (scheduled quarterly ones and any out-of-bounds) to the Zulu builds of OpenJDK 7 until at least December 2027. Read More * Developer Tools * Getting Started * Java Core * Simon Ritter Jul 12, 2022 * Are Java Security Updates Important? Recently, I was in discussion with a Java user at a bank about the possibilities of using Azul Platform Core to run a range of applications. Security is a very serious concern when sensitive data is in use, and potentially huge sums of money could be stolen. I was, therefore, somewhat taken aback when the user said, “We’re not worried about installing Java updates as our core banking services are behind a firewall.” Read More * Security * Simon Ritter Aug 03, 2021 * Much Ado About Nothing in Java Occasionally something in Java pops up that I thought I knew about, but it turns out I didn’t appreciate all the subtle details. This was recently the case for “nul”. Before I started using Java, the main programming language I used was C. This was great for things like operating systems and device drivers because it uses explicit pointers. References to data are through a numerical address that can be manipulated if required. Although null might seem like a simple, straightforward concept, there are some edge cases that make its use require a little more thought. I hope this provides you with a better understanding of nothing (null). Read More * Getting Started * Simon Ritter Feb 23, 2021 AUTHOR(S) * Simon Ritter * * Deputy CTO at Azul Systems COMMENTS (1) Leave a Comment CANCEL REPLY Your email address will not be published. Required fields are marked * Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language. Save my name, email, and website in this browser for the next time I comment. Post Comment Δ Java Annotated Month-to-month – October 2022 - LunaticTech […] Use Pattern Matching to Simplify Java – If you happen to’re on the lookout for a easy rationalization of Sample Matching, then this piece is for you! It exhibits how you need to use Sample Matching to make your code concise with out shedding readability, and why it pays to take action. […] 7:44 pm, October 3, 2022 foojay.io Friends of OpenJDK OPENJDK HUB * Releases * Distros * Command Line COMMUNITY HUB * Foojay Today * Events Calendar ABOUT * About Us * Advisory Board * hello@foojay.io * Sitemap * Terms of Use SET EVENT REMINDER * Microsoft Outlook * Google Calendar * macOS Calendar SUBSCRIBE TO FOOJAY UPDATES: https://foojay.io/feed/ Copied to the clipboard By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View Cookie Policy Cookies Settings Reject All Accept All Cookies PRIVACY PREFERENCE CENTER * YOUR PRIVACY * FUNCTIONAL COOKIES * TARGETING COOKIES * PERFORMANCE COOKIES * STRICTLY NECESSARY COOKIES YOUR PRIVACY When you visit any website, it may store or retrieve information on your browser, mostly in the form of cookies. This information might be about you, your preferences or your device and is mostly used to make the site work as you expect it to. The information does not usually directly identify you, but it can give you a more personalized web experience. Because we respect your right to privacy, you can choose not to allow some types of cookies. Click on the different category headings to find out more and change our default settings. However, blocking some types of cookies may impact your experience of the site and the services we are able to offer. FUNCTIONAL COOKIES Functional Cookies These cookies enable the website to provide enhanced functionality and personalisation. They may be set by us or by third party providers whose services we have added to our pages. If you do not allow these cookies then some or all of these services may not function properly. TARGETING COOKIES Targeting Cookies These cookies may be set through our site by our advertising partners. They may be used by those companies to build a profile of your interests and show you relevant adverts on other sites. They do not store directly personal information, but are based on uniquely identifying your browser and internet device. If you do not allow these cookies, you will experience less targeted advertising. PERFORMANCE COOKIES Performance Cookies These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. All information these cookies collect is aggregated and therefore anonymous. If you do not allow these cookies we will not know when you have visited our site, and will not be able to monitor its performance. STRICTLY NECESSARY COOKIES Always Active These cookies are necessary for the website to function and cannot be switched off in our systems. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms. You can set your browser to block or alert you about these cookies, but some parts of the site will not then work. These cookies do not store any personally identifiable information. Back Button BACK Filter Button Consent Leg.Interest checkbox label label checkbox label label checkbox label label Clear checkbox label label Apply Cancel Confirm My Choices Reject All Allow All PRIVACY PREFERENCE CENTER * YOUR PRIVACY * FUNCTIONAL COOKIES * TARGETING COOKIES * PERFORMANCE COOKIES * STRICTLY NECESSARY COOKIES YOUR PRIVACY When you visit any website, it may store or retrieve information on your browser, mostly in the form of cookies. This information might be about you, your preferences or your device and is mostly used to make the site work as you expect it to. The information does not usually directly identify you, but it can give you a more personalized web experience. Because we respect your right to privacy, you can choose not to allow some types of cookies. Click on the different category headings to find out more and change our default settings. However, blocking some types of cookies may impact your experience of the site and the services we are able to offer. FUNCTIONAL COOKIES Functional Cookies These cookies enable the website to provide enhanced functionality and personalisation. They may be set by us or by third party providers whose services we have added to our pages. If you do not allow these cookies then some or all of these services may not function properly. TARGETING COOKIES Targeting Cookies These cookies may be set through our site by our advertising partners. They may be used by those companies to build a profile of your interests and show you relevant adverts on other sites. They do not store directly personal information, but are based on uniquely identifying your browser and internet device. If you do not allow these cookies, you will experience less targeted advertising. PERFORMANCE COOKIES Performance Cookies These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. All information these cookies collect is aggregated and therefore anonymous. If you do not allow these cookies we will not know when you have visited our site, and will not be able to monitor its performance. STRICTLY NECESSARY COOKIES Always Active These cookies are necessary for the website to function and cannot be switched off in our systems. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms. You can set your browser to block or alert you about these cookies, but some parts of the site will not then work. These cookies do not store any personally identifiable information. Back Button BACK Filter Button Consent Leg.Interest checkbox label label checkbox label label checkbox label label Clear checkbox label label Apply Cancel Confirm My Choices Reject All Allow All