aboutsummaryrefslogtreecommitdiff
path: root/website/features/experimental/ExtensionMethod.html
blob: b2c751b91d11ef19813057eefb40bd7d09d12bdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<!DOCTYPE html>
<html><head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<link rel="stylesheet" type="text/css" href="../../logi/reset.css" />
	<link rel="stylesheet" type="text/css" href="../features.css" />
	<link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" />
	<meta name="description" content="Spice up your java" />
	<title>EXPERIMENTAL - @ExtensionMethod</title>
</head><body><div id="pepper">
	<div class="minimumHeight"></div>
	<div class="meat">
		<div class="header"><a href="../../index.html">Project Lombok</a></div>
		<h1>@ExtensionMethod</h1>
		<div class="byline">Annoying API? Fix it yourself: Add new methods to existing types!</div>
		<div class="since">
			<h3>Since</h3>
			<p>
				@ExtensionMethod was introduced as experimental feature in lombok v0.11.2.
			</p>
		</div>
		<div class="experimental">
			<h3>Experimental</h3>
			<p>
			Experimental because:
			<ul>
				<li>High-impact on code style</li>
				<li>Really would like to ship with utility methods to expand common classes, but so far lombok doesn't have a good distribution method for such runtime dependencies</li>
				<li>Affects quite a bit of eclipse, and auto-complete e.d. do not work yet in netbeans</li>
				<li>Should @ExtensionMethod be legal on methods? Should it be legal on packages?</li>
			</ul>
			Current status: <em>positive</em> - Currently we feel this feature may move out of experimental status with no or minor changes soon.
		</div>
		<div class="overview">
			<h3>Overview</h3>
			<p>
				You can make a class containing a bunch of <code>public</code>, <code>static</code> methods which all take at least 1
				parameter. These methods will extend the type of the first parameter, as if they were instance methods, using the
				<code>@ExtensionMethod</code> feature.
			</p>
			</p><p>
				For example, if you create <code>public static String toTitleCase(String in) { ... }</code>, you can use the
				<code>@ExtensionMethod</code> feature to make it look like the <code>java.lang.String</code> class has a method named
				<code>toTitleCase</code>, which has no arguments. The first argument of the static method fills the role of <code>this</code>
				in instance methods.
			</p><p>
				All methods that are <code>public</code>, <code>static</code>, and have at least 1 argument whose type is not primitive, are
				considered extension methods, and each will be injected into the namespace of the type of the first parameter as if they were
				instance methods. As in the above example, a call that looks like: <code>foo.toTitleCase()</code> is replaced with
				<code>ClassContainingYourExtensionMethod.toTitleCase(foo);</code>. Note that it is actually not an instant
				<code>NullPointerException</code> if <code>foo</code> is null - it is passed like any other parameter.
			</p><p>
				You can pass any number of classes to the <code>@ExtensionMethod</code> annotation; they will all be searched for
				extension methods. These extension methods apply for any code that is in the annotated class.
			</p><p>
				Lombok does not (currently) have any runtime dependencies which means lombok does not (currently) ship with any useful
				extension methods so you'll have to make your own. However, here's one that might spark your imagination:
				<pre>public class ObjectExtensions {
	public static &lt;T&gt; or(T object, T ifNull) {
		return object != null ? object : ifNull;
	}
}</pre>
			With the above class, if you add <code>@ExtensionMethod(ObjectExtensions.class)</code> to your class definition, you can write:
			<pre>String x = null;
System.out.println(x.or("Hello, World!"));</pre>
			The above code will not fail with a <code>NullPointerException</code>; it will actually output <code>Hello, World!</code>
			</p>
		</div>
		<div class="snippets">
			<div class="pre">
				<h3>With Lombok</h3>
				<div class="snippet">@HTML_PRE@</div>
			</div>
			<div class="sep"></div>
			<div class="post">
				<h3>Vanilla Java</h3>
				<div class="snippet">@HTML_POST@</div>
			</div>
		</div>
		<div style="clear: left;"></div>
		<div class="overview">
			<h3>Small print</h3><div class="smallprint">
				<p>
					Calls are rewritten to a call to the extension method; the static method itself is not inlined. Therefore, the 
					extension method must be present both at compile and at runtime.
				</p><p>
					Generics is fully applied to figure out extension methods. i.e. if the first parameter of your extension method is
					<code>List&lt;? extends String&gt;</code>, then any expression that is compatible with that will have your extension method,
					but other kinds of lists won't. So, a <code>List&lt;Object&gt;</code> won't get it, but a <code>List&lt;String&gt;</code> will.
				</p>
			</div>
		</div>
		<div class="footer">
			<a href="index.html">Back to experimental features</a> | <a href="Accessors.html">Previous feature (@Accessors)</a> | <a href="FieldDefaults.html">Next feature (@FieldDefaults)</a><br />
			<a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
		</div>
		<div style="clear: both;"></div>
	</div>
</div>
<script type="text/javascript">
	var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
	document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
	try {
		var pageTracker = _gat._getTracker("UA-9884254-1");
		pageTracker._trackPageview();
	} catch(err) {}
</script>
</body></html>