根据我对java 8 lambda表达式的理解,如果我们不在" - >"之后包含代码。在花括号中,将隐式返回值。但是在下面的例子中,forEach
方法需要Consumer
并且表达式返回值,但编译器没有在Eclipse中给出错误。
List<StringBuilder> messages = Arrays.asList(new StringBuilder(), new StringBuilder());
messages.stream().forEach(s-> s.append("helloworld"));//works fine
messages.stream().forEach((StringBuilder s)-> s.append("helloworld")); //works fine
messages.stream().forEach(s-> s); // doesn't work , Void methods cannot return a value
messages.stream().forEach(s-> s.toString()); // works fine
messages.stream().forEach(s-> {return s.append("helloworld");}); // doesn't work , Void methods cannot return a value
messages.stream().forEach((StringBuilder s)-> {return s.append("helloworld");}); // doesn't work , Void methods cannot return a value
s.append
返回StringBuilder
,s.toString()
返回String
,但lambda将其视为void
。
我在这里缺少什么?当我们在对象上调用方法时,为什么编译器没有给出错误?
答案 0 :(得分:11)
来自JLS 15.27.3. Type of a Lambda Expression:
如果全部的话,lambda表达式与函数类型一致 以下是真实的:
函数类型没有类型参数。
lambda参数的数量与函数类型的参数类型的数量相同。
如果明确键入lambda表达式,则其形式参数类型与函数类型的参数类型相同。
如果假设lambda参数与函数类型的参数类型具有相同的类型,则:
如果函数类型的结果为void,则lambda主体是语句表达式(第14.8节)或与void兼容的块。
如果函数类型的结果是(非void)类型R,那么i)lambda body是一个与R兼容的表达式 在赋值上下文中,或ii)lambda体是值兼容的 块,每个结果表达式(第15.27.2节)与R in兼容 作业背景。
上面突出显示的句子意味着任何语句lambda表达式(即没有块的lambda表达式)匹配单个方法的返回类型为void
的函数接口(例如Consumer
所需的forEach
功能接口。 s.append("helloworld")
方法)。
这解释了为什么s.toString()
&amp; void-compatible
(您的1,2和4示例)可以作为语句lambda表达式正常工作。
示例5&amp; 6不起作用,因为它们阻塞了lambda体,它们是与值兼容的lambda表达式。要成为return;
,所有返回语句都不能返回任何内容(即只有void-compatible
)。
另一方面,以下messages.stream().forEach(s-> {s.append("helloworld");});
messages.stream().forEach(s-> {s.append("helloworld"); return;});
块lambda实体将通过编译:
messages.stream().forEach(s-> s);
您的第4个示例 - void method (StringBuilder s)
{
s;
}
因以下方法未通过编译的原因相同而无效:
t1.n1=t1.n1-t2.n2
答案 1 :(得分:4)
从java.util.stream.Stream
开始,forEach
的签名为:
void forEach(Consumer<? super T> action)
从java.util.function.Consumer
开始,action
必须实施以下方法:
void accept(T t)
在您的所有不起作用的示例中,您返回的T
与void
的返回类型不匹配。
为什么编译器在对象上调用方法时没有给出错误?
因为您没有尝试return
某事,所以lambda的返回类型为void
,与所需的Consumer
签名相匹配。
s -> s
唯一可能的类型是T -> T
,而(StringBuilder s) -> s.append()
可能是StringBuilder -> ()
,满足void
要求。
答案 2 :(得分:1)
Sub ImportMyData()
Dim filter, caption, importFileName As String
Dim importWb As Workbook
Dim targetSh, validationSh As Worksheet
Dim targetTb As ListObject
Dim importRg, targetRg, validationRg As Range
Dim i, j, k, targetStartRow As Integer
' Set speed related application settings (this will be restored on exit)
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.DisplayStatusBar = False
.EnableEvents = False
End With
' Set definitions
Set targetSh = ThisWorkbook.Sheets("myTargetSheet")
Set targetTb = targetSh.ListObjects("myTargetTable")
Set targetRg = targetTb.DataBodyRange
Set validationSh = ThisWorkbook.Sheets("myValidationSheet")
Set validationRg = validationSh.Range("myValidationRange")
' Set filter for the file choose dialog
filter = "Text files (*.xlsx),*.xlsx"
' Set UI text for file choose dialog
caption = "Chose xlsx file to import "
' Set filename from UI dialog
importFileName = Application.GetOpenFilename(Filter, , Caption)
' Show Form to get user input for extra field (will return variable 'myChoice')
ImportFormPicker.Show
' Open the import file workbook
Set importWb = Application.Workbooks.Open(importFileName)
importWb.Windows(1).Visible = False
targetSh.Activate
' Set definitions
Set importRg = importWb.Worksheets(1).UsedRange
' Unprotects target sheet
targetSh.Unprotect
' Get starting row of imported target range for future reference
targetStartRow = targetTb.ListRows.Count + 1
' Iterate all rows in import range
For i = 1 To importRg.Rows.Count
' Only import row if first cell in row is a date
If IsDate(importRg.Cells(i, 1).Value) Then
' Count imported rows
k = k + 1
' Insert row at end of target table
targetTb.ListRows.Add AlwaysInsert:=True
' Iterate all columns in import range
For j = 1 To importRg.Columns.Count
With targetRg.Cells(targetTb.ListRows.Count, j)
' Import value
.Value = importRg.Cells(i, j).Value
' Set format according to validation range
.NumberFormat = validationRg.Cells(2, j).NumberFormat
End With
Next j
With targetRg.Cells(targetTb.ListRows.Count, j)
' Add custom value which was determined by user form
.Value = Butik
' Set Format according to validation range
.NumberFormat = validationRg.Cells(2, j).NumberFormat
End With
' --- Speed troubleshooting = 100 rows imported/~8seconds.
If i Mod 100 = 0 Then
ThisWorkbook.Activate
End If
' --- End Speed troubleshooting
End If
Next i
' Close the import file workbook without saving
importWb.Close savechanges:=False
' Protect target sheet
With targetSh
' Protect the target sheet
.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True
' Show the target sheet
.Visible = True
' Activate the target sheet
.Activate
End With
' Select imported range
targetRg.Range(Cells(targetStartRow, 1), Cells(targetTb.ListRows.Count, j)).Select
' Show user how many rows were imported
MsgBox ("Imported " & k & " rows.")
' Restore speed related settings
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
.DisplayStatusBar = True
.EnableEvents = True
End With
End Sub
需要一个实现一个方法的消费者
Stream.forEach(Consumer)
即。它无法返回任何东西。
如果你想要返回一些东西,你必须对返回的值做一些事情。
答案 3 :(得分:1)